Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove horizontal and vertical lines from an image

I have an image that is of a text written on a spiral notebook paper. the paper has horizontal lines. I would like to remove the horizontal lines from the image.

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

While running it on my image I get these results:

Original Image

Resulting 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've tried ImageMagik on my original image as well in an effort to remove lines.

I get better results with ImageMagik but still not completely accurate.

convert original -morphology close:3 "1x5: 0,1,1,1,0" original_im.jpg
like image 228
Anthony Avatar asked Feb 25 '17 20:02

Anthony


People also ask

How do I remove vertical lines from an image in Python?

One approach is to rotate the image 90 deg, then apply your same code, then rotate back 90 deg. Another approach is to change your horizontal kernel to a vertical kernel in your morphology.

How do you remove vertical lines?

Delete lines or connectorsClick the line, connector, or shape that you want to delete, and then press Delete. Tip: If you want to delete multiple lines or connectors, select the first line, press and hold Ctrl while you select the other lines, and then press Delete.

Why are there horizontal lines in my photos?

Horizontal lines may be recorded on a still image when a flash with High Speed Sync (HSS) is combined with a fast shutter speed. This is due to the tiny fluctuations in the amount of light emitted by the flash during the exposure period. If you experience this, try the following settings: Use a slower shutter speed.


1 Answers

Your case is less trivial than the one provided in the tutorial that you have based your solution on. With this approach you will not be able to filter the lines in 100%, because of the fact that horizontal parts of the characters will sometimes be treated as lines.

Depends on your expectations (which you haven't really specified) and specifically the accuracy that you expect, you might want to try to find the characters instead of finding the line. That should provide you with more robustness.

Regarding your code, by adding few lines of code right after finding horizontal lines on the image (before verticalsize = rows / 30 line of code), you can get some results. I've worked on a half size image.

Result with horizontalsize = int(cols/30)

Result with horizontalsize = int(cols/15)

Again, I'm stressing that those will never be accurate with that approach in your case. Here's the 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 provided are somewhat satisfactory. I've also used int conversion, since that's what the getStructuringElement function expects: horizontalsize = int(cols / 30).

You can also try some smoothing and morphology on the result. That should make the characters a little bit more readable.

like image 110
m3h0w Avatar answered Nov 02 '22 20:11

m3h0w