Ramon Griffo
Ramon Griffo

Reputation: 343

How to detect lines in noisy line images?

I generate noisy images with certain lines in them, like this one:

Generated image

I'm trying to detect the lines using OpenCV, but something is going wrong.

Here's my code so far, including the code to generate the noisy images.

import cv2
import numpy as np

def draw_random_lines(img, w, n):
    for i in range(n):
        point1 = (np.random.randint(low = 0, high = w), np.random.randint(low = 0, high = w))
        point2 = (np.random.randint(low = 0, high = w), np.random.randint(low = 0, high = w))
        cv2.line(img,point1,point2,(255,0,0),5)
    x = y = 0
    while(y<w):
        while(x<w):
            if(np.any(img[x, y] != 0)):
                if(np.random.randint(low=0, high=100) < 60):
                    img[x, y] = [255, 255, 255] 
                else:
                    img[x, y] = [0, 0, 0]
            else:
                if(np.random.randint(low=0, high=100) < 95):
                    img[x, y] = [255, 255, 255] 
                else:
                    img[x, y] = [0, 0, 0]
            x+=1
        x=0
        y+=1
    return img

w = 512
img = np.zeros((w,w,3), np.uint8)
img = draw_random_lines(img, w, 5)
cv2.imshow("Original", img)
cv2.imwrite("alo.png", img)
img = cv2.imread("alo.png")

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)

lines = cv2.HoughLines(edges,1,np.pi/180,200)
for line in lines:
    for rho,theta in line:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        x1 = int(x0 + 1000*(-b))
        y1 = int(y0 + 1000*(a))
        x2 = int(x0 - 1000*(-b))
        y2 = int(y0 - 1000*(a))

        cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)


cv2.imshow("Detectada", img)

cv2.waitKey(0)

And here are the results I'm getting (very wrong):

Wrong Results

So, how can I properly detect the lines in these noisy images?

Upvotes: 6

Views: 9523

Answers (1)

HansHirse
HansHirse

Reputation: 18925

Since OpenCV's Hough transform implementations look for white pixels on black background, the first important step for finding the lines is to invert your noisy images.

Slight median blurring will further help to get rid of the noise, thus improving the performance of the Hough transform.

For my suggested solution, I also used the HoughLinesP method instead of HoughLines. (From my experience, you'll get "better" results.)

So, here's my code snippet:

import cv2
import numpy as np

# Read input
img = cv2.imread('images/K9YLm.png', cv2.IMREAD_GRAYSCALE)

# Initialize output
out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# Median blurring to get rid of the noise; invert image
img = 255 - cv2.medianBlur(img, 3)

# Detect and draw lines
lines = cv2.HoughLinesP(img, 1, np.pi/180, 10, minLineLength=50, maxLineGap=30)
for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(out, (x1, y1), (x2, y2), (0, 0, 255), 2)

cv2.imshow('out', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

The output out looks like this:

Output

Due to the usage of HoughLinesP, you get a quite large set of (smaller) lines. One would need to setup a kind of "grouping" of similar lines. (Or, maybe one could just draw the red lines on a separate image, and re-run the line detection.)

Hope that helps!

Upvotes: 12

Related Questions