Ir al contenido

← Todas las funcionalidades

Inspección visual (visión artificial)Raspberry Pi + cámara USBUSB/V4L2Visión artificial

Template matching tolerante a rotación para inspección pass/fail

El template matching de OpenCV a secas falla en cuanto una pieza llega ligeramente girada — y en una cinta transportadora real, las piezas siempre lo hacen. En un despliegue real de inspección visual en línea de producción, la solución fue sencilla: rotar la imagen capturada de -15 a +15 grados en pasos de 2 grados, ejecutar cv2.matchTemplate con TM_CCOEFF_NORMED en cada ángulo y quedarse con la mejor puntuación. Una puntuación de 0.85 o superior significa que el marcaje impreso coincide con la referencia golden: la pieza pasa.

Por qué rotar la captura y no la plantilla

La referencia es una imagen golden capturada y preprocesada con cuidado — conviene no tocarla para que las puntuaciones sigan siendo comparables entre piezas y turnos. Rotar la captura en vivo (con relleno de bordes para que las esquinas sobrevivan a cv2.warpAffine) mantiene la plantilla intacta. El rango de búsqueda de ±15° cubre lo que una pieza puede girar de forma realista en el utillaje; cualquier valor mayor es un error de posicionamiento que de todos modos merece rechazo.

TM_CCOEFF_NORMED como puntuación pass/fail

El coeficiente de correlación normalizado es invariante a cambios globales de brillo y devuelve una puntuación limpia de 0 a 1, así que un único umbral funciona durante toda la jornada. En el sistema desplegado, 0.85 separa las impresiones correctas de los marcajes ausentes, emborronados o equivocados con margen por ambos lados. Registra la mejor puntuación y el ángulo de cada pieza: una puntuación que deriva lentamente es tu aviso temprano de que el enfoque o la iluminación se han movido.

Ajustar el paso de ángulo frente al tiempo de ciclo

Dieciséis ángulos en pasos de 2° suponen dieciséis llamadas a matchTemplate por pieza — todavía muy por debajo de un segundo en una Raspberry Pi con la entrada recortada y binarizada del pipeline de preprocesado. Si tus piezas giran menos, estrecha el rango antes de reducir el paso: menos ángulos aportan más velocidad que ángulos más finos, y una resolución de 2° ya es más fina que la propia curva de puntuación.

Un fragmento de la implementación

Tal cual del ejemplo desplegado en el Raspberry Pi + cámara USB — cópialo libremente:

def binary_silkscreen(text="IS-42", angle=0.0, noise=False):
    """Generates a binary silkscreen image, optionally rotated."""
    img = np.zeros((200, 300), np.uint8)
    cv2.putText(img, text, (60, 120), cv2.FONT_HERSHEY_SIMPLEX,
                1.5, 255, 4)
    if angle:
        M = cv2.getRotationMatrix2D((150, 100), angle, 1.0)
        img = cv2.warpAffine(img, M, (300, 200))
    if noise:  # simulates stray pixels left by the adaptive threshold
        salt = np.random.rand(*img.shape) > 0.995
        img[salt] = 255
    return img

El ejemplo completo es un programa entero — cabecera de conexionado, setup y bucle principal — listo para adaptar a tu aplicación.

Preguntas frecuentes

¿Por qué no usar feature matching como ORB o SIFT?

Las impresiones binarizadas tienen pocos keypoints estables, y el feature matching añade complejidad de ajuste. Para una cámara fija que comprueba un marcaje conocido, la búsqueda exhaustiva de rotación sobre template matching es más simple, determinista y suficientemente rápida.

¿Cómo se eligió el umbral de 0.85?

Empíricamente, registrando las puntuaciones de piezas buenas y defectuosas conocidas. Las piezas buenas se agrupaban por encima de 0.90 y las defectuosas por debajo de 0.75, así que 0.85 deja margen de seguridad en ambas direcciones.

¿Y si mis piezas pueden llegar con cualquier ángulo?

Amplía el bucle a 360 grados con una primera pasada gruesa y refina después alrededor del mejor ángulo. El ejemplo mantiene ±15° porque el utillaje limita la orientación en la línea real.

Funcionalidades relacionadas