Saltar al contenido

Python + OpenCV: Segmentación de imágenes OCR

Esta es la respuesta más correcta que encomtrarás aportar, pero primero mírala pausadamente y valora si se puede adaptar a tu proyecto.

Solución:

Un excelente tutorial sobre el primer paso que describiste está disponible en pyimagesearch (y tienen excelentes tutoriales en general)

En resumen, como lo describe Ella, tendrías que usar cv2.CHAIN_APPROX_SIMPLE. Un método un poco más robusto sería usar cv2.RETR_LIST en vez de cv2.RETR_EXTERNAL y luego ordene las áreas, ya que debería funcionar decentemente incluso en fondos blancos/si la página inscribe una forma más grande en el fondo, etc.

Llegando a la segunda parte de su pregunta, una buena manera de segmentar los personajes sería usar el Extractor de región extremal máximamente estable disponible en OpenCV. Una implementación completa en CPP está disponible aquí en un proyecto en el que estuve ayudando recientemente. La implementación de Python seguiría las líneas de (El código a continuación funciona para OpenCV 3.0+. Para la sintaxis de OpenCV 2.x, compruébelo en línea)

import cv2

img = cv2.imread('test.jpg')
mser = cv2.MSER_create()

#Resize the image so that MSER can work better
img = cv2.resize(img, (img.shape[1]*2, img.shape[0]*2))

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()

regions = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions[0]]
cv2.polylines(vis, hulls, 1, (0,255,0)) 

cv2.namedWindow('img', 0)
cv2.imshow('img', vis)
while(cv2.waitKey()!=ord('q')):
    continue
cv2.destroyAllWindows()

Esto da la salida como

ingrese la descripción de la imagen aquí

Ahora bien, para eliminar la false positivos, simplemente puede recorrer los puntos en los cascos y calcular el perímetro (suma de la distancia entre todos los puntos adyacentes en los cascos[i]donde los cascos[i] es una lista de todos los puntos en un convexHull). Si el perímetro es demasiado grande, clasifíquelo como que no es un personaje.

Las líneas de diagnóstico a lo largo de la imagen vienen porque el borde de la imagen es negro. que simplemente se puede eliminar agregando la siguiente línea tan pronto como se lea la imagen (debajo de la línea 7)

img = img[5:-5,5:-5,:]

que da la salida

ingrese la descripción de la imagen aquí

La opción en la parte superior de mi cabeza requiere la extracción de 4 esquinas de la imagen sesgada. Esto se hace usando cv2.CHAIN_APPROX_SIMPLE en vez de cv2.CHAIN_APPROX_NONE al encontrar contornos. Después, podrías usar cv2.approxPolyDP y esperemos que permanezca con las 4 esquinas del recibo (si todas sus imágenes son como esta, entonces no hay razón por la que no debería funcionar).

Ahora usa cv2.findHomography y cv2.wardPerspective para rectificar la imagen según los puntos de origen que son los 4 puntos extraídos de la imagen sesgada y los puntos de destino que deberían formar un rectángulo, por ejemplo, las dimensiones de la imagen completa.

Aquí puede encontrar ejemplos de código y más información: OpenCV-Transformaciones geométricas de imágenes

También esta respuesta puede ser útil – SO – Detectar y corregir texto sesgado

EDITAR: Se corrigió la segunda cadena aproximadamente a cv2.CHAIN_APPROX_NONE.

El preprocesamiento de la imagen mediante la conversión del texto deseado en primer plano a negro y el fondo no deseado a blanco puede ayudar a mejorar la precisión de OCR. Además, eliminar las líneas horizontales y verticales puede mejorar los resultados. Aquí está la imagen preprocesada después de eliminar el ruido no deseado, como las líneas horizontales/verticales. Tenga en cuenta el borde eliminado y las líneas de la tabla

ingrese la descripción de la imagen aquí

import cv2

# Load in image, convert to grayscale, and threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find and remove horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (35,2))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, (0,0,0), 3)

# Find and remove vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,35))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, (0,0,0), 3)

# Mask out unwanted areas for result
result = cv2.bitwise_and(image,image,mask=thresh)
result[thresh==0] = (255,255,255)

cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey()

Aquí puedes ver las comentarios y valoraciones de los lectores

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *