6

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?

HansHirse
  • 18,010
  • 10
  • 38
  • 67
Ramon Griffo
  • 333
  • 5
  • 14

1 Answers1

12

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!

HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • “maybe one could just draw the red lines on a separate image, and re-run the line detection” This seems quite redundant to me. If OpenCV gives access to the parameter space, a bit of smoothing there and a better way of detecting local maxima would go a long way to fix the multiple detections per line problem. – Cris Luengo Jun 14 '19 at 13:25
  • @CrisLuengo I haven't properly searched before, but there seems to be [this promising Q&A](https://stackoverflow.com/questions/45531074/). I'll test their solution(s) next week - and then keep that piece of code nearby. – HansHirse Jun 14 '19 at 15:04