How can I use standard image processing filters (from OpenCV) to remove long horizontal and vertical lines from an image?
The images are B&W so removing means simply painting black.
Illustration:
I'm currently doing it in Python, iterating over pixel rows and cols and detecting ranges of consecutive pixels, removing those that are longer than N pixels. However, it's really slow in comparison to the OpenCV library, and if there's a way of accomplishing the same with OpenCV functions, that'll likely be orders of magnitude faster.
I imagine this can be done by convolution using a kernel that's a row of pixels (for horizontal lines), but I'm having a hard time figuring the exact operation that would do the trick.
To remove Horizontal Lines from an image you can use an edge detection algorithm to detect edges and then use Hough's Transform in OpenCV to detect lines and color them white:
import cv2
import numpy as np
img = cv2.imread(img,0)
laplacian = cv2.Laplacian(img,cv2.CV_8UC1) # Laplacian Edge Detection
minLineLength = 900
maxLineGap = 100
lines = cv2.HoughLinesP(laplacian,1,np.pi/180,100,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(img,(x1,y1),(x2,y2),(255,255,255),1)
cv2.imwrite('Written_Back_Results.jpg',img)
if your lines are truly horizontal/vertical, try this
import cv2
import numpy as np
img = cv2.imread('c:/data/test.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
linek = np.zeros((11,11),dtype=np.uint8)
linek[5,...]=1
x=cv2.morphologyEx(gray, cv2.MORPH_OPEN, linek ,iterations=1)
gray-=x
cv2.imshow('gray',gray)
cv2.waitKey(0)
result
You can refer OpenCV Morphological Transformations documentation for more details.
How long is "long". Long, as in, lines that run the length of the entire image, or just longer than n
pixels?
If the latter, then you could just use an n+1
X n+1
median or mode filter, and set the corner coefficients to zero, and you'd get the desired effect.
If you're referring to just lines that run the width of the entire image, just use the memcmp()
function against a row of data, and compare it to a pre-allocated array of zeros which is the same length as a row. If they are the same, you know you have a blank line that spans the horizontal length of the image, and that row can be deleted.
This will be MUCH faster than the element-wise comparisons you are currently using, and is very well explained here:
Why is memcpy() and memmove() faster than pointer increments?
If you want to repeat the same operation for vertical lines, just transpose the image, and repeat the operation.
I know this is more of a system-optimization level approach than an openCV filter like you requested, but it gets the job done fast and safely. You can speed up the calculation even more if you manage to force the image and your empty array to be 32-bit aligned in memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With