Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 815
Ramon Griffo Avatar asked Mar 03 '23 20:03

Ramon Griffo


1 Answers

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!

like image 95
HansHirse Avatar answered Mar 12 '23 12:03

HansHirse