Reconocimiento de imágenes de PCB en formato BMP
Principal ] Arriba ]

 

 

Diferenciando los agujeros y el borde de las pistas del circuito impreso:

El objetivo del programa es interpretar una imagen en mapa de bits con el dibujo un circuito por la cara de pistas. Debería reconocer el borde de todas las pistas y los agujeros para ordenar a la fresadora que mecanice la placa. Esto no se puede hacer de cualquier manera sino que cada punto de los bordes debe ser detectado siguiendo un orden secuencial ya que en este mismo orden se desbastará el cobre en la placa.

El algoritmo que utilizo permite de un solo paso detectar todos los bordes correctamente y al mismo tiempo diferenciar cuales son agujeros para que la maquina también pueda taladrar automáticamente.

Hay que tener en cuenta que la herramienta de la fresadora tiene un ancho y, por tanto, hay que desbastar siguiendo el borde pero separado de él una distancia R para que la maquina no destroce también la pista. R es el radio de la punta de desbaste. Para conseguir esto ejecuto este mismo algoritmo N veces hasta que las pistas engordan (virtualmente) lo suficiente como para compensar este efecto. Cada vez que se ejecuta se añade el borde calculado a la imagen real para aumentar el grosor de las pistas. (El reconocimiento de los agujeros se hace solo la 1º vez).

Se puede entender todo el código del programa dividiéndolo en 3 partes conceptuales aunque realmente están demasiado entrelazadas como para separarlas. Hay una parte general que controla todo el flujo del programa, otra que detecta todo el borde de cada pista, y otra que diferencia los agujeros.

 

  • Control de flujo general

Se hace un barrido de toda la imagen que mira uno a uno todos los píxeles de izquierda a derecha y de arriba abajo. Se mira el color del píxel, que solo puede ser o blanco (no hay pista) o negro (hay pista). Cuando se detecta un cambio de blanco a negro al pasar de un píxel al que está a su derecha entonces se da cuenta de que ha dado con una pista y se ejecuta el algoritmo de detección del borde. Cuando se ha rodeado por completo esa pista se vuelve al punto anterior y se continúa con el barrido buscando otra pista nueva. Para evitar que se repita la detección de la misma pista varias veces he incluido una matriz en la que cada valor del punto (x,y) tiene memorizado si pertenece a una pista ya encontrada o no.

Además tuve que hacer que el programa considerara que los puntos fuera de la imagen son blancos así no puede trabajar con placas cuyas pistas tocan el borde de la imagen sin dar errores raros...

Como dije en la introducción se debe tener en cuenta el grosor de la herramienta y por tanto hacer que desbaste siguiendo un borde un poco alejado del borde real y así no destruir las pistas que sean delgadas. La manera más fácil que se me ocurrió de detectar un borde separado del real es hacer este proceso descrito anteriormente varias veces y añadiendo cada borde hallado a la imagen real engordando las pistas. El número de veces que se repita este proceso equivale al número de píxeles que se separa la herramienta de la pista. Cuando se conozca la relación entre píxel y distancia física sobre la placa se modificará este parámetro automáticamente indicando cual es el diámetro de la herramienta.

 

  • Reconocimiento de los agujeros

Esto se realiza al mismo tiempo que la detección de los bordes. Cada vez que el control de flujo explicado anteriormente encuentra una nueva pista pone a cero una variable llamada HoleLong que medirá el número de puntos que tiene el borde de esa pista, es decir su perímetro. A cada nuevo punto encontrado de este borde HoleLong se incrementa en uno.

En el caso de que la pista que se está rodeando sea un agujero entonces este perímetro es justamente la longitud de la circunferencia de este agujero. Entonces para discriminar ya con mucha precisión cuales son agujeros e determinado que, por ejemplo las pistas con un perímetro HoleLong menor que 25 son razonablemente pequeñas y por tanto pueden ser un agujero.

Ahora suponiendo que lo es se procede a calcular su centro. Para ello teniendo el perímetro lo más fácil que se me ocurrió fue ir almacenando en una lista todos los puntos (x,y) del perímetro (esto se realiza mientras se haya el borde). Sabiendo qué puntos son se puede trazar una recta atravesando la circunferencia y dividiendo su longitud en dos se haya el centro. Para hacer esta recta necesito dos puntos. Uno es el ultimo de la lista que tengo y el otro es aquel que está justo en la mitad de la lista, es decir "longitud de circunferencia" / 2 

Para el ejemplo de la imagen HoleLong = 12 ya que el borde encontrado (puntos rojos) contiene 12 píxeles. Aunque en el ejemplo puse el 1 en lugar equivocado (tenia que esta en el lugar del 7), el efecto sería el mismo.

Si el ultimo píxel tiene las coordenadas Xf, Yf, el que está en la mitad del perímetro es Xm, Ym y el centro del agujero es Xc, Yc:

Xc = (Xf + Xm)/2     y     Yc = (Yf + Ym)/2 

Con esto ya llega para detectar todos los agujeros de la placa pero así se detectarán también algunas cosas que no son agujeros, como puntos negros y pequeños en la placa o algo parecido a un agujero pero con forma no circular, que puede ser por ejemplo el hueco de una letra para escribir en el cobre. Conociendo el centro ahora se pueden discriminar estos con bastante facilidad:

Los puntos negros se diferencian obviamente mirando el color del punto central, si este es negro es que no es un agujero.

Pero para determinar que la forma es aproximadamente circular hay que complicarse algo más la vida, como hacer un barrido siguiendo una circunferencia de radio un poco mayor que el real y ver que todos sus puntos son negros, así se entiende que los blancos están contenidos y por tanto es un agujero. Pero este no es el método que he usado porque al probarlo rechazaba algunos agujeros verdaderos. Esto es culpa de la mala resolución y la imperfección de los agujeros.

Así que he probado otro método menos preciso pero más rápido y más eficaz teniendo en cuanta las características que suele tener una placa...

Consiste simplemente en medir el diámetro en dirección del eje X pasando por el centro y hacer lo mismo midiendo según la dirección del eje Y. Comprobar si son prácticamente iguales (aplicando un margen de error ajustable por el usuario). Si lo son se entiende que es un agujero por tener un diámetro constante. Aún así no diferenciaría por ejemplo una elipse oblicua de un agujero pero esa es una situación prácticamente imposible.

Por este método se detectan absolutamente todos los agujeros de la placa independientemente de su diámetro (hasta un máximo ajustable) y discrimina prácticamente todas las cosas parecidas a un agujero que se podrían confundir. Aún así sigue siendo imposible diferenciar por ejemplo el hueco de la letra "o" escrita en la placa, aunque la letra sea cursiva. Hay algunos tipos de letra alta o inclinada que son ideales para esto pues no los confunde. Aún así estoy ya conforme pues si de 200 agujeros selecciona por error 3 de más estos se pueden eliminar manualmente antes de grabar la placa con otra aplicación que haré para quitar y poner agujeros nuevos.

Aunque no lo he hecho todavía, no sería nada difícil hacer que diferencie los diámetros de los agujeros para ordenar a la máquina pararse para cambiar de broca.

 

  • Detectar los bordes

Para esto empleo un algoritmo intuitivo aunque más difícil de implementar de lo que parece. Basándome en que todas las pistas y agujeros de la placa son conjuntos acotados de puntos (están limitados por las dimensiones de la placa) se puede considerar que cada nudo del circuito eléctrico tiene una pista que está aislada de las demás y por tanto se puede bordear por completo.

Una vez detectada una pista nueva con el control de flujo, se entra en un bucle que explora uno a uno todos los puntos de su borde hasta que llega al punto por el que había empezado, entonces sale del bucle y vuelve al control general.

La pregunta es ¿Como hace un programa para saber cual es el siguiente punto del borde?

Sencillamente hay que explorar todos los puntos adyacentes al actual en sentido de las agujas del reloj hasta que detecte de nuevo un cambio de color blanco a negro. En este momento descubre un nuevo punto del borde y realiza lo mismo pero girando alrededor de este nuevo punto.

Para entenderlo de manera más precisa he hecho la imagen de arriba. Hay que leerla de izquierda a derecha y de arriba abajo. Se presentan 14 situaciones que ocurren una detrás de la otra para acabar rodeando por completo la hipotética pista eléctrica, que son los píxeles negros.

Los puntos negros son puntos de la pista que aun no han sido encontrados por el programa.

Los puntos azules son aquellos que ya han sido detectados y que forman parte del borde.

El punto rojo se corresponde con el pixel del borde que ha sido encontrado previamente y alrededor del cual se busca otro nuevo punto girando en sentido CW.

Este giro de búsqueda lo indico con la flecha roja, que acaba naturalmente donde encuentra un nuevo punto de la pista y empieza desde una posición (ángulo) calculada previamente.

Las flechas azules indican el giro de búsqueda que se realizo anteriormente y por el cual se encontró el punto rojo (actual).

El cuadrado con contorno verde es el que indica la posición desde la que se debe empezar a buscar. Observar la relación que hay entre las flechas azules y los cuadrados verdes. El cuadrado verde se coloca en aquella posición que resulte de prolongar el radio de giro de la flecha verde en el momento en que acaba. Así que, por ejemplo, en la fase numero 3 como la flecha azul llega por abajo al punto rojo (con un ángulo de 270º), el cuadrado verde se pone en la posición 45º más adelante, es decir, 315º. Hay que considerar el punto rojo como el centro de estos ángulos.

En la fase numero 1 el punto rojo ha sido encontrado por el programa de control de flujo mientras hacía el barrido de izquierda a derecha, por eso la flecha azul es recta y no un arco.

Como se ve aunque un punto determinado del borde ya haya sido explorado este se vuelve a detectar si el programa vuelve a pasar por el (por causa de que la pista tiene anchura de 1 píxel en ese punto). Esto no importa en absoluto.

Todos los puntos que va detectando (azules) se almacenan en una lista indicando sus posiciones X,Y para posteriormente enviar a la maquina y los trabaje secuencialmente. Se almacenan seguidos incluso los puntos pertenecientes a pistas diferentes ya que cuando cuando el programa de grabado detecte una distancia mayor que 1 entre el punto que se esta desbastando y el siguiente ordenará a la máquina que se pare, levante el taladro de la placa, lo posicione en el nuevo punto, encienda de nuevo, baje y continúe...