2017-10-04 9 views
1

Je veux extraire des caractères manuscrits qui sont écrits dans des boîtes comme ceci. Je suis en train d'extraire des carrés d'une largeur de 29 pixels, ce qui me donne des images comme celles-ci.Comment supprimer les bordures d'images prises d'un document (comme les caractères manuscrits MNIST)?

Extracted images 1Extracted Images 2Extracted Images 3

Pour reconnaître correctement les caractères, les images de caractère individuel doivent être extrêmement propres. Comme cela,

Clean chars 1Clean chars 2

Qu'est-ce que je fais est,

  1. Calculer la projection horizontale et verticale de chaque image.
  2. Effectuez une itération sur chaque élément des deux matrices. Si la valeur de la projection est supérieure à un certain seuil, cela signifie qu'elle n'a pas rencontré la frontière. Il supprime les espaces autour de la frontière.

  3. Puis trouvez les contours dans l'image.

  4. Si la zone de contour est supérieure à un certain seuil. Obtenez le rectangle de délimitation et recadrez-le.

Mais le problème est que la méthode n'est pas très précise. Dans certains cas, cela fonctionne bien, mais dans la plupart des cas, si elle échoue lamentablement. Il produit des images comme,

enter image description hereenter image description here

également les valeurs de projection sont très spécifiques à cette image (ou des images plus proches de cette image). Ça ne généralise pas bien.

Y a-t-il une autre méthode qui peut fonctionner dans cette situation?

Le code,

char = cv2.imread(image) 
char_gray = cv2.cvtColor(char, cv2.COLOR_BGR2GRAY) 
char_bw = cv2.adaptiveThreshold(char_gray, 255, 
cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 9) 

(rows, cols) = char_gray.shape 

bit_not = cv2.bitwise_not(char_bw) 
proj_h = cv2.reduce(bit_nv2.REDUCE_AVG) 

proj_v = cv2.reduce(bit_not, 0, cv2.REDUCE_AVG) 

thresh_h = 200 
thresh_v = 100 

start_x, start_y, end_x, end_y = 0, 0, cols - 1, rows - 1 
#proj_h = proj_h[0] 
proj_v = proj_v[0] 

num_iter_h = cols // 8 
num_iter_v = rows // 8 

for _ in range(num_iter_h): 
    if proj_h[start_y][0] > 35: 
     start_y += 1 

for _ in range(num_iter_h): 
    if proj_h[end_y][0] > 160: 
     end_y -= 1 

for _ in range(num_iter_v): 
    if proj_v[start_x] > 15: #25: 
     start_x += 1 

for _ in range(num_iter_v): 
    if proj_v[end_x] > 125: 
     end_x -= 1 

print('processing.. %s.png' % idx) 
output_char = char[start_y:end_y, start_x:end_x] 
output_char = get_cropped_char(output_char) 
return output_char 


def get_cropped_char(img): 
    """ 
    Returns Grayscale cropped image 
    """ 

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

blur = cv2.GaussianBlur(img, (3,3), 0) 

thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 75, 10) 
im2, cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 

contour = None 
for c in cnts: 
    area = cv2.contourArea(c) 
    if area > 100: 
     contour = c 
if contour is None: return None 
(x, y, w, h) = cv2.boundingRect(contour) 
img = img[y:y+h, x:x+w] 
return img 

Répondre

1

Je ne pense pas que ce soit une bonne méthode pour recadrer directement le charbon après seuil l'image. Je crois que morphy-op peut faire de la scène. Les éléments du bloc sont arrangés correctement, alors essayez morphy-erode-op pour séparer les blocs (ou supprimez les bordures des blocs). Une fois que vous obtenez l'image chars clean, vous pouvez facilement recadrer les images char.

...

mauvais anglais, 哈哈哈


Ce résultat est que je reçois.

Images recadrées.

enter image description here

Les étapes:

enter image description here

+0

Parlez-vous d'une opération d'érosion? – Arka

+0

oui, vous l'avez. – Silencer

+0

Wow. C'est exactement ce que je veux faire. Mais, après s'être érodé. Comment séparez-vous les boîtes? – Arka

1

Je suis nouveau à OpenCV (et je travaille sur le projet similaire ...), mais voici ce que je peux dire par expérience. Extraire les caractères propres est possible, au moins pour les deux derniers. Le premier est un peu plus difficile à cause de la ligne qui traverse le numéro.

Vous devez faire la version grise de l'image, seuil et essayer quelques opening/closing operations. Après cela, vous devez faire morphological transformation pour supprimer les lignes horizontales/verticales de chaque carré. J'ai essayé avec ma version du programme et il fait le travail pour un 40%. Je dois l'améliorer ...

Après cela, avec le résultat, vous devez extraire la boîte de délimitation de chaque nombre. Ce n'est pas difficile. Certains nombres échoueront, mais la plupart d'entre eux seront extraits. "Extrêmement propre" est assez difficile à obtenir à ce niveau.

Faire plus de recherche. Il y a beaucoup d'exemples de la façon de faire la plupart des opérations.

EDIT: vous devez avoir l'image semblable à la mienne. Travailler sur quelque chose comme cela est plus facile ..

example

Voici ce que j'obtenus grâce à moi: regardez les carrés internes, chacun autour du seul numéro. Ils peuvent être facilement extraits et sauvegardés pour le traitement suivant.

example2

+0

Je suis aussi assez nouveau pour OpenCV. Je me bats avec ces problèmes depuis quelques semaines. Comme les résultats ne sont pas cohérents, j'ai au moins 5 approches à chaque étape. Dans votre cas, commencez par supprimer les lignes horizontales/verticales en ouvrant/fermant, puis en détectant les contours, puis la zone de contour des contours détectés? – Arka

+0

Eh bien, j'utilise OpenCV et Python depuis 3 mois ... Le processus que j'utilise est proche de celui que vous avez décrit, opération plus ou moins. – Link

+0

Avec quelle précision avez-vous pu supprimer les limites de votre image? – Arka