Python: Segmentación de imágenes como proceso previo para clasificación

¿Qué técnica recomienda para segmentar los caracteres en esta imagen para que estén listos para alimentar un modelo como los que se usan con el conjunto de datos MNIST; porque toman un personaje a la vez. Esta pregunta no tiene en cuenta la importancia de transformar la imagen y su binarización.

¡Gracias!

introduzca la descripción de la imagen aquí

Como punto de partida probaría lo siguiente:

  1. Utilice el umbral de OTSU.
  2. A continuación, realice algunas operaciones morfológicas para eliminar el ruido y aislar cada dígito.
  3. Ejecutar labling componente conectado.
  4. Alimente cada componente conectado a su clasificador para que reconozca el dígito si el puntaje de clasificación es bajo descarte.
  5. La validación final espera que todo el dígito esté más o menos en línea y en más o menos una distancia constante entre sí.

Aquí están las primeras 4 etapas. Ahora necesita agregar su software de reconocimiento para reconocer los dígitos.

import cv2 import numpy as np from matplotlib import pyplot as plt # Params EPSSILON = 0.4 MIN_AREA = 10 BIG_AREA = 75 # Read img img = cv2.imread('i.jpg',0) # Otzu threshold a,thI = cv2.threshold(img,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # Morpholgical se = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(1,1)) thIMor = cv2.morphologyEx(thI,cv2.MORPH_CLOSE,se) # Connected compoent labling stats = cv2.connectedComponentsWithStats(thIMor,connectivity=8) num_labels = stats[0] labels = stats[1] labelStats = stats[2] # We expect the conneccted compoennt of the numbers to be more or less with a constats ratio # So we find the medina ratio of all the comeonets because the majorty of connected compoent are numbers ratios = [] for label in range(num_labels): connectedCompoentWidth = labelStats[label,cv2.CC_STAT_WIDTH] connectedCompoentHeight = labelStats[label, cv2.CC_STAT_HEIGHT] ratios.append(float(connectedCompoentWidth)/float(connectedCompoentHeight)) # Find median ratio medianRatio = np.median(np.asarray(ratios)) # Go over all the connected component again and filter out compoennt that are far from the ratio filterdI = np.zeros_like(thIMor) filterdI[labels!=0] = 255 for label in range(num_labels): # Ignore biggest label if(label==1): filterdI[labels == label] = 0 continue connectedCompoentWidth = labelStats[label,cv2.CC_STAT_WIDTH] connectedCompoentHeight = labelStats[label, cv2.CC_STAT_HEIGHT] ratio = float(connectedCompoentWidth)/float(connectedCompoentHeight) if ratio > medianRatio + EPSSILON or ratio < medianRatio - EPSSILON: filterdI[labels==label] = 0 # Filter small or large compoennt if labelStats[label,cv2.CC_STAT_AREA] < MIN_AREA or labelStats[label,cv2.CC_STAT_AREA] > BIG_AREA: filterdI[labels == label] = 0 plt.imshow(filterdI) # Now go over each of the left compoenet and run the number recognotion stats = cv2.connectedComponentsWithStats(filterdI,connectivity=8) num_labels = stats[0] labels = stats[1] labelStats = stats[2] for label in range(num_labels): # Crop the bounding box around the component left = labelStats[label,cv2.CC_STAT_LEFT] top = labelStats[label, cv2.CC_STAT_TOP] width = labelStats[label, cv2.CC_STAT_WIDTH] height = labelStats[label, cv2.CC_STAT_HEIGHT] candidateDigit = labels[top:top+height,left:left+width] # plt.figure(label) # plt.imshow(candidateDigit) 

OTSU thrshold imagen

Me conecto a la respuesta de Amitay.

Para el 2: utilizaría el adelgazamiento como operación morfológica (mire el algoritmo de adelgazamiento en opencv )

Para el 3: Y en OpenCV 3.0 ya existe una función llamada cv :: connectedComponents )

Espero eso ayude