¿Cuál es la mejor manera de detectar las esquinas de una factura / recibo / hoja de papel en una foto? Esto se utilizará para la corrección de perspectiva posterior, antes del OCR.
Mi enfoque actual ha sido:
RGB> Gray> Canny Edge Detection con umbralización> Dilate (1)> Elimina objetos pequeños (6)> clear boarder objects> elige un blog grande basado en el área convexa. > [detección de esquinas - No implementado]
No puedo evitar pensar que debe haber un enfoque "inteligente" / estadístico más sólido para manejar este tipo de segmentación. No tengo muchos ejemplos de entrenamiento, pero probablemente podría juntar 100 imágenes.
Contexto mas amplio:
Estoy usando matlab para crear prototipos y planeo implementar el sistema en OpenCV y Tesserect-OCR. Este es el primero de una serie de problemas de procesamiento de imágenes que necesito resolver para esta aplicación específica. Así que estoy buscando desarrollar mi propia solución y volver a familiarizarme con los algoritmos de procesamiento de imágenes.
Aquí hay una imagen de muestra que me gustaría que manejara el algoritmo: Si desea aceptar el desafío, las imágenes grandes están en http://madteckhead.com/tmp
(fuente: madteckhead.com )
(fuente: madteckhead.com )
(fuente: madteckhead.com )
(fuente: madteckhead.com )
En el mejor de los casos, esto da:
(fuente: madteckhead.com )
(fuente: madteckhead.com )
(fuente: madteckhead.com )
Sin embargo, falla fácilmente en otros casos:
(fuente: madteckhead.com )
(fuente: madteckhead.com )
(fuente: madteckhead.com )
¡Gracias de antemano por todas las grandes ideas! ¡Me gusta tanto!
EDITAR: Hough Transform Progress
P: ¿Qué algoritmo agruparía las suficientes líneas para encontrar esquinas? Siguiendo los consejos de las respuestas, pude usar la transformación de Hough, seleccionar líneas y filtrarlas. Mi enfoque actual es bastante tosco. Supuse que la factura siempre estará a menos de 15 grados fuera de alineación con la imagen. Termino con resultados razonables para las líneas si este es el caso (ver más abajo). Pero no estoy completamente seguro de un algoritmo adecuado para agrupar las líneas (o votar) para extrapolar las esquinas. Las líneas de Hough no son continuas. Y en las imágenes ruidosas, puede haber líneas paralelas, por lo que se requiere alguna forma o distancia de las métricas del origen de la línea. ¿Algunas ideas?
(fuente: madteckhead.com )
fuente
Respuestas:
Soy el amigo de Martin que estaba trabajando en esto a principios de este año. Este fue mi primer proyecto de codificación, y terminó con un poco de prisa, por lo que el código necesita algo errr ... decodificación ... Daré algunos consejos de lo que ya te he visto hacer, y luego ordenar mi código en mi día libre mañana.
El primer consejo,
OpenCV
ypython
es genial, muévete hacia ellos lo antes posible. :REEn lugar de eliminar objetos pequeños o ruido, baje las astutas restricciones, para que acepte más bordes, y luego encuentre el contorno cerrado más grande (en OpenCV use
findcontour()
con algunos parámetros simples, creo que uséCV_RETR_LIST
). aún podría tener problemas cuando está en una hoja de papel blanco, pero definitivamente estaba brindando mejores resultados.Para la
Houghline2()
Transformación, intente con elCV_HOUGH_STANDARD
en lugar deCV_HOUGH_PROBABILISTIC
, le dará valores rho y theta , definiendo la línea en coordenadas polares, y luego puede agrupar las líneas dentro de una cierta tolerancia a esos.Mi agrupación funcionó como una tabla de búsqueda, para cada línea generada por la transformación hough daría un par rho y theta. Si estos valores estaban dentro de, digamos, el 5% de un par de valores en la tabla, se descartaron, si estaban fuera de ese 5%, se agregó una nueva entrada a la tabla.
A continuación, puede analizar las líneas paralelas o la distancia entre líneas con mucha más facilidad.
Espero que esto ayude.
fuente
Un grupo de estudiantes de mi universidad demostró recientemente una aplicación para iPhone (y una aplicación Python OpenCV) que habían escrito para hacer exactamente esto. Según recuerdo, los pasos eran algo así:
Esto pareció funcionar bastante bien y pudieron tomar una foto de una hoja de papel o libro, realizar la detección de esquinas y luego mapear el documento en la imagen en un plano casi en tiempo real (había una sola función OpenCV para realizar el mapeo). No había OCR cuando lo vi funcionar.
fuente
Esto es lo que se me ocurrió después de un poco de experimentación:
No es perfecto, pero al menos funciona para todas las muestras:
fuente
for line in lines[0]: cv2.line(edges, (line[0], line[1]), (line[2], line[3]), (255,0,0), 2, 8) # finding contours contours, _ = cv2.findContours(edges.copy(), cv.CV_RETR_EXTERNAL, cv.CV_CHAIN_APPROX_TC89_KCOS) contours = filter(lambda cont: cv2.arcLength(cont, False) > 100, contours) contours = filter(lambda cont: cv2.contourArea(cont) > 10000, contours)
En lugar de comenzar desde la detección de bordes, puede utilizar la detección de esquinas.
Marvin Framework proporciona una implementación del algoritmo Moravec para este propósito. Podrías encontrar las esquinas de los papeles como punto de partida. Debajo de la salida del algoritmo de Moravec:
fuente
También puede utilizar MSER (regiones extremas máximamente estables) sobre el resultado del operador Sobel para encontrar las regiones estables de la imagen. Para cada región devuelta por MSER, puede aplicar un casco convexo y una aproximación de poli para obtener algunos como este:
Pero este tipo de detección es útil para la detección en vivo más que una sola imagen que no siempre arroja el mejor resultado.
fuente
Después de la detección de bordes, use Hough Transform. Luego, coloque esos puntos en una SVM (máquina de vectores de soporte) con sus etiquetas, si los ejemplos tienen líneas suaves, SVM no tendrá ninguna dificultad para dividir las partes necesarias del ejemplo y otras partes. Mi consejo sobre SVM, pon un parámetro como conectividad y longitud. Es decir, si los puntos están conectados y son largos, es probable que sean una línea del recibo. Luego, puede eliminar todos los demás puntos.
fuente
Aquí tienes el código de @Vanuan usando C ++:
fuente
std::vector<cv::Vec4i> lines;
se declara en un alcance global en mi proyecto.Convertir en espacio de laboratorio
Utilice el clúster del segmento 2 de kmeans
fuente