How to find 4 lines of this white blob with HoughLines?

1k Views Asked by At

i am trying to draw 4 lines on every side of the white rectangle using Houghlines method.
This is the image i am working on Source image (2592 x 1246 image).

import cv2 as cv
import numpy as np
img = cv.imread("picture_compress.bmp")
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(img_gray, 100, 200, 5)
lines = cv.HoughLines(edges, rho=2, theta=np.pi / 180, threshold=200)  # lines will be in polar coordinate system
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (255, 0, 255), (255, 255, 0), (0, 255, 255)]

for i, line in enumerate(lines):
    rho, theta = line[0]    # rho --> distance from the coordinate origin (0,0) (Top-Left corner of the image)
                            # theta --> line rotation angle in radius
    # getting the cos(theta) and sin(theta) value
    a = np.cos(theta)
    b = np.sin(theta)
    # getting the origin value(top-left corner of the image)
    x0 = a * rho
    y0 = b * rho
    # 2 points
    pt1 = (int(x0 + 2592 * (-b)), int(y0 + 2592 * a))
    pt2 = (int(x0 - 2592 * (-b)), int(y0 - 2592 * a))
    # draw lines on the input image
    cv.line(img, pt1, pt2, colors[i % len(colors)], thickness=3, lineType=cv.LINE_AA)
print("Total number of lines:", str(len(lines)))
cv.namedWindow("Hough", cv.WINDOW_NORMAL)
cv.imshow("Hough", img)
cv.waitKey(0)

the result i am i getting Result.

From the last image you can see that multiple lines are drawn on the edges of the white blob.

Tasks:

  1. What is the best way to draw only 4 lines on each side of the rectangle ?
  2. How can i get 4 finite lines by using only HoughLines only and not HoughLinesP ?

-------------------------------------------------- EDITED (17/03/2021) --------------------------------------------------

Let me post the Original image which i am working on.

Fase 1: Eroded_Dilated_Image - the result after applying erosion and dilation and filling the blob. The code for this:

# This function is used for cleaning the image
def erode_dilate(img, num_iter):                    
    kernel = np.ones((3, 3), np.uint8)
    erosion = cv.erode(src=img, kernel=kernel, iterations=num_iter)
    dilation = cv.dilate(src=erosion, kernel=kernel, iterations=num_iter) 
    return dilation

# This function will search for the blob with max area and will fill it
def find_draw_big_blob(img): 
    contours, _ = cv.findContours(image=img, mode=cv.RETR_TREE, method=cv.CHAIN_APPROX_SIMPLE)
    contour_area = [cv.contourArea(cnt) for cnt in contours]      # List of contours' area
    id_max_area = np.argmax(contour_area)     
    label_max_image = np.zeros(img.shape)
    draw_max_contour = cv.drawContours(image=label_max_image, contours=contours, contourIdx=id_max_area, color=255, thickness=-1)  

img = cv.imread("25559.bmp")
gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret1, thresh = cv.threshold(gray_image, thresh=127, maxval=255, type=cv.THRESH_OTSU)
image_erode_dilate = erode_dilate(img=thresh, num_iter=2)
big_blob = find_draw_big_blob(img=image_erode_dilate)
cv.imshow("Image", big_blob)

Fase 2: houghlines_Image - the final result after applying hough trasform. The code i used for this hough transform is already up in the question.

But the final result is not the result that i want.
I would like to achieve the following result shown in this sample_image

2

There are 2 best solutions below

3
Ahx On
  • What is the best way to draw only 4 lines on each side of the rectangle ?

The best way to draw only 4-lines on each side of the rectangle is using fast-line-detector

Below you can see how fast-line-detector works:

enter image description here

Code:


# Load the library
import cv2

# Load the image
img = cv2.imread("BWzd2.png")

# Convert to gray-scale
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Init. the fast-line-detector (fld)
fld = cv2.ximgproc.createFastLineDetector().detect(gry)

# Detect the lines
for line in fld:

    # Get current coordinates
    x1 = int(line[0][0])
    y1 = int(line[0][1])
    x2 = int(line[0][2])
    y2 = int(line[0][3])

    # Draw the line
    cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 5)

# Display
cv2.imshow("img", img)
cv2.waitKey(0)

Result:

enter image description here

8
fmw42 On

In your Python/OpenCV code, simply increase your threshold to 250 or double your theta angle.

Input:

enter image description here

1) Increase threshold

lines = cv.HoughLines(edges, rho=2, theta=np.pi / 180, threshold=250)  # lines will be in polar coordinate system

import cv2 as cv
import numpy as np
img = cv.imread("picture_compress.png")
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(img_gray, 100, 200, 5)
lines = cv.HoughLines(edges, rho=2, theta=np.pi / 180, threshold=250)  # lines will be in polar coordinate system
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (255, 0, 255), (255, 255, 0), (0, 255, 255)]

result = img.copy()
for i, line in enumerate(lines):
    rho, theta = line[0]    # rho --> distance from the coordinate origin (0,0) (Top-Left corner of the image)
                            # theta --> line rotation angle in radius
    # getting the cos(theta) and sin(theta) value
    a = np.cos(theta)
    b = np.sin(theta)
    # getting the origin value(top-left corner of the image)
    x0 = a * rho
    y0 = b * rho
    # 2 points
    pt1 = (int(x0 + 2592 * (-b)), int(y0 + 2592 * a))
    pt2 = (int(x0 - 2592 * (-b)), int(y0 - 2592 * a))
    # draw lines on copy of the input image
    cv.line(result, pt1, pt2, colors[i % len(colors)], thickness=3, lineType=cv.LINE_AA)
print("Total number of lines:", str(len(lines)))
cv.namedWindow("Hough", cv.WINDOW_NORMAL)
cv.imshow("Hough", result)
cv.waitKey(0)

cv.imwrite("picture_compress_lines1.png", result)

enter image description here

2) Increase your theta, e.g. double it:

lines = cv.HoughLines(edges, rho=2, theta=2*np.pi / 180, threshold=200)  # lines will be in polar coordinate system

import cv2 as cv
import numpy as np
img = cv.imread("picture_compress.png")
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(img_gray, 100, 200, 5)
lines = cv.HoughLines(edges, rho=2, theta=2*np.pi / 180, threshold=200)  # lines will be in polar coordinate system
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (255, 0, 255), (255, 255, 0), (0, 255, 255)]

result = img.copy()
for i, line in enumerate(lines):
    rho, theta = line[0]    # rho --> distance from the coordinate origin (0,0) (Top-Left corner of the image)
                            # theta --> line rotation angle in radius
    # getting the cos(theta) and sin(theta) value
    a = np.cos(theta)
    b = np.sin(theta)
    # getting the origin value(top-left corner of the image)
    x0 = a * rho
    y0 = b * rho
    # 2 points
    pt1 = (int(x0 + 2592 * (-b)), int(y0 + 2592 * a))
    pt2 = (int(x0 - 2592 * (-b)), int(y0 - 2592 * a))
    # draw lines on copy of the input image
    cv.line(result, pt1, pt2, colors[i % len(colors)], thickness=3, lineType=cv.LINE_AA)
print("Total number of lines:", str(len(lines)))
cv.namedWindow("Hough", cv.WINDOW_NORMAL)
cv.imshow("Hough", result)
cv.waitKey(0)

cv.imwrite("picture_compress_lines2.png", result)

enter image description here

The textual data from the Hough lines says:

Total number of lines: 5

But I only see 4 lines.