Chris
Chris

Reputation: 28064

HoughLinesP not detecting expected lines

I'm trying out OpenCV to do some image processing. Admittedly I'm a noob at this stuff, but I feel like I'm wrapping my brain around it somewhat. I'm using a mask to detect the lighter areas of the image, then running a canny detector and finally a HoughLinesP detection. Code is below. The result I'm getting is:

enter image description here

What I expected (and desire) is more like below (notice red lines on result):

enter image description here

For what it's worth, my end game is to auto rotate the image so the receipt is straight. If I'm taking the wrong path entirely, advise would be appreciated.

import cv2
import numpy as np
from matplotlib import pyplot


def detect_lines(img):

    temp = cv2.cvtColor(img,cv2.COLOR_BGR2HLS)
    lower = np.uint8([0, 160, 0])
    upper = np.uint8([255, 255, 255])
    white_mask = cv2.inRange(temp, lower, upper)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.blur(gray, (3, 3))

    canny_low = 100
    edges = cv2.Canny(white_mask, canny_low, canny_low * 3, apertureSize=5)
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, 10, 2, 80)

    result = img.copy()
    if lines is not None:
        for x in range(0, len(lines)):
            for x1, y1, x2, y2 in lines[x]:
                print(x1, y1, x2, y2)
                cv2.line(result, (x1, y1), (x2, y2), (255, 0, 0), 2)

    pyplot.subplot(141), pyplot.imshow(img, cmap='gray')
    pyplot.title('Original Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(142), pyplot.imshow(white_mask, cmap='gray')
    pyplot.title('Gray Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(143), pyplot.imshow(edges, cmap='gray')
    pyplot.title('Edge Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(144), pyplot.imshow(result, cmap='gray')
    pyplot.title('Result Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.show()
    return img


if __name__ == '__main__':

    image = cv2.imread('receipt.jpg')
    image = detect_lines(image)
    cv2.imwrite('output.jpg', image)

Upvotes: 0

Views: 1442

Answers (1)

Christoffer
Christoffer

Reputation: 558

I would suggest start looking at different Morphological Transformations which you can apply to your canny edge detection in order to improve the hough line transform.

This is not perfect but it's something to get you started:

import cv2
import numpy as np
from matplotlib import pyplot


def detect_lines(img):

    temp = cv2.cvtColor(img,cv2.COLOR_BGR2HLS)
    kernel = np.ones((5, 5), np.uint8) # < --- Added a kernel you can differ
    lower = np.uint8([0, 160, 0])
    upper = np.uint8([255, 255, 255])
    white_mask = cv2.inRange(temp, lower, upper)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.blur(gray, (3, 3))

    canny_low = 100
    edges = cv2.Canny(white_mask, canny_low, canny_low * 3, apertureSize=3)
    dilate = cv2.dilate(edges, kernel, iterations=2) # < --- Added a dilate, check link I provided
    ero = cv2.erode(dilate, kernel, iterations=1) # < --- Added an erosion, check link I provided
    lines = cv2.HoughLinesP(dilate, 1, np.pi/180, 10, 2, 80)

    result = img.copy()
    if lines is not None:
        for x in range(0, len(lines)):
            for x1, y1, x2, y2 in lines[x]:
                print(x1, y1, x2, y2)
                cv2.line(result, (x1, y1), (x2, y2), (255, 0, 0), 2)

    pyplot.subplot(151), pyplot.imshow(img, cmap='gray')
    pyplot.title('Original Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(152), pyplot.imshow(white_mask, cmap='gray')
    pyplot.title('Mask Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(153), pyplot.imshow(edges, cmap='gray')
    pyplot.title('Edge Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.subplot(154), pyplot.imshow(ero, cmap='gray')
    pyplot.title('Dilate/Erosion Image'), pyplot.xticks([]), pyplot.yticks([]) # <--- Added a display

    pyplot.subplot(155), pyplot.imshow(result, cmap='gray')
    pyplot.title('Result Image'), pyplot.xticks([]), pyplot.yticks([])

    pyplot.show()
    return result # <--- You want to return the result right?


if __name__ == '__main__':

    image = cv2.imread('receipt.jpg')
    image = detect_lines(image)
    cv2.imwrite('output.jpg', image)

enter image description here

Another approach could be looking into Corner Detection and then drawing a line between the detected corners (I haven't tried this approach but it's just for inspiration :) ).

Upvotes: 2

Related Questions