How to remove horizontal and vertical lines from an image

I have an image written on spiral notebook paper. paper has horizontal lines. I would like to remove horizontal lines from the image.

While googling, I found a solution that I thought would work: Extracting horizontal and vertical lines using morphological operations The solution was in C ++, so I converted it to Python. It works well on the sample provided in this solution, however it does not work for my images.

When run on my image, I get the following results:

Source image

Final image

Below is the Python code that I translated from 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() 

I tried ImageMagik on my original image, and also in an attempt to delete the lines.

I get the best results with ImageMagik , but still not entirely accurate.

 convert original -morphology close:3 "1x5: 0,1,1,1,0" original_im.jpg 
+5
source share
1 answer

Your case is less trivial than the one indicated in the textbook on which you based your decision. With this approach, you will not be able to filter lines 100% because the horizontal parts of characters are sometimes treated as strings.

Depending on your expectations (which you did not actually specify) and, in particular, the precision you expect, you may try to find characters instead of searching for a string. This should provide you with greater reliability.

As for your code, adding a few lines of code immediately after searching for horizontal lines in the image (up to the line verticalsize = rows / 30 code), you can get some results. I worked on the image at half the size.

Result with horizontalsize = int (cols / 30)

Result with horizontalsize = int (cols / 15)

Again, I emphasize that this will never be accurate with this approach in your case. Here is a snippet:

 #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() 

Try playing with horizontalsize if the images I have provided are somewhat satisfactory. I also used an int conversion, since the getStructuringElement function expects: horizontalsize = int(cols / 30) .

You can also try smoothing and morphology of the result. This should make the characters more readable.

+4
source

Source: https://habr.com/ru/post/1264718/


All Articles