web-dev-qa-db-fra.com

Comment supprimer des lignes horizontales et verticales d'une image

J'ai une image qui est d'un texte écrit sur un papier de cahier à spirale. le papier a des lignes horizontales. Je voudrais supprimer les lignes horizontales de l'image.

Pendant la recherche sur Google, j'ai trouvé une solution qui, selon moi, fonctionnerait: Extraire les lignes horizontales et verticales en utilisant des opérations morphologiques La solution était en C++, donc je l'ai convertie en Python. Cela fonctionne bien sur l'exemple d'image fourni dans cette solution, mais il ne semble pas fonctionner pour mes images.

En l'exécutant sur mon image, j'obtiens ces résultats:

Image originale

Image résultante

Ci-dessous se trouve le code Python que j'ai traduit de C++

 #cpp code converted from     http://docs.opencv.org/3.2.0/d1/dee/tutorial_moprh_lines_detection.html

import cv2
import numpy as np

img = cv2.imread("original.jpg")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

img = cv2.bitwise_not(img)
th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2)
cv2.imshow("th2", th2)
cv2.imwrite("th2.jpg", th2)
cv2.waitKey(0)
cv2.destroyAllWindows()

horizontal = th2
vertical = th2
rows,cols = horizontal.shape
horizontalsize = cols / 30
horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontalsize,1))
horizontal = cv2.erode(horizontal, horizontalStructure, (-1, -1))
horizontal = cv2.dilate(horizontal, horizontalStructure, (-1, -1))
cv2.imshow("horizontal", horizontal)
cv2.imwrite("horizontal.jpg", horizontal)
cv2.waitKey(0)
cv2.destroyAllWindows()

verticalsize = rows / 30
verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize))
vertical = cv2.erode(vertical, verticalStructure, (-1, -1))
vertical = cv2.dilate(vertical, verticalStructure, (-1, -1))
cv2.imshow("vertical", vertical)
cv2.imwrite("vertical.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

vertical = cv2.bitwise_not(vertical)
cv2.imshow("vertical_bitwise_not", vertical)
cv2.imwrite("vertical_bitwise_not.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step1
edges = cv2.adaptiveThreshold(vertical,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2)
cv2.imshow("edges", edges)
cv2.imwrite("edges.jpg", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step2
kernel = np.ones((2, 2), dtype = "uint8")
dilated = cv2.dilate(edges, kernel)
cv2.imshow("dilated", dilated)
cv2.imwrite("dilated.jpg", dilated)
cv2.waitKey(0)
cv2.destroyAllWindows()

# step3
smooth = vertical.copy()

#step 4
smooth = cv2.blur(smooth, (4,4))
cv2.imshow("smooth", smooth)
cv2.imwrite("smooth.jpg", smooth)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step 5
(rows, cols) = np.where(img == 0)
vertical[rows, cols] = smooth[rows, cols]

cv2.imshow("vertical_final", vertical)
cv2.imwrite("vertical_final.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

J'ai également essayé ImageMagik sur mon image d'origine dans le but de supprimer les lignes.

J'obtiens de meilleurs résultats avec ImageMagik mais toujours pas complètement précis.

convert original -morphology close:3 "1x5: 0,1,1,1,0" original_im.jpg
9
Anthony

Votre cas est moins trivial que celui fourni dans le tutoriel sur lequel vous avez basé votre solution. Avec cette approche, vous ne pourrez pas filtrer les lignes à 100%, car les parties horizontales des caractères seront parfois traitées comme des lignes.

Cela dépend de vos attentes (que vous n'avez pas vraiment spécifiées) et en particulier de la précision que vous attendez, vous voudrez peut-être essayer de trouver les personnages au lieu de trouver la ligne. Cela devrait vous fournir plus de robustesse.

En ce qui concerne votre code, en ajoutant quelques lignes de code juste après avoir trouvé des lignes horizontales sur l'image (avant la ligne de code verticalsize = rows / 30), Vous pouvez obtenir des résultats. J'ai travaillé sur une image demi-taille.

Résultat avec horizontalalsize = int (cols/30)

Résultat avec horizontalalsize = int (cols/15)

Encore une fois, je souligne que ceux-ci ne seront jamais exacts avec cette approche dans votre cas. Voici l'extrait:

#inverse the image, so that lines are black for masking
horizontal_inv = cv2.bitwise_not(horizontal)
#perform bitwise_and to mask the lines with provided mask
masked_img = cv2.bitwise_and(img, img, mask=horizontal_inv)
#reverse the image back to normal
masked_img_inv = cv2.bitwise_not(masked_img)
cv2.imshow("masked img", masked_img_inv)
cv2.imwrite("result2.jpg", masked_img_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()

Essayez de jouer avec horizontalsize si les images que j'ai fournies sont quelque peu satisfaisantes. J'ai également utilisé la conversion int, car c'est ce que la fonction getStructuringElement attend: horizontalsize = int(cols / 30).

Vous pouvez également essayer un lissage et une morphologie du résultat. Cela devrait rendre les caractères un peu plus lisibles.

5
m3h0w