opencvimage-processingcomputer-visionedge-detection

Horizontal Line detection and measure distance in between with OpenCV


Hi I'm quite new in OpenCV, I am currently trying to detect horizontal lines in an image using HoughLinesP function in opencv, in order to calculate the ratio between x and y. The line detection result is shown in the second picture.

original image

result image

  1. How to ignore the vertical lines and only detect horizontal lines?
  2. The egde detected by HoughLinesP seems not a single line. Is there a better way to detect the edge as a single line instead of multiple lines merged together?
  3. How should I proceed to the next step of getting the ratio between x and y?

Thank you in advance!

import cv2
import numpy as np

# read image
img = cv2.imread('testtube.png')

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# apply canny edge detection
edges = cv2.Canny(gray, 90, 100,apertureSize=3)

# get hough lines
result = img.copy()

lines = cv2.HoughLinesP(edges, rho=1,theta=np.pi/2, threshold=30,lines=np.array([]), minLineLength=30,maxLineGap=20)
a,b,c = lines.shape
for i in range(a):
    cv2.line(result, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 2, cv2.LINE_AA)

cv2.imshow("edges", edges)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

Solution

  • Here is my approach.

    1- Check vertically all pixels. Ignore white pixels. Vertically count black pixels(<15), count other non-white pixels. Keep these counts in a variable.

    2- Do this for each vertical column which are not white at all. For each columnd counts keep in an array.

    3- get the average of all non-black and black pixel counts inside the array. This will statistically give good results.

    For the following applied code I get the x and y length as 273.906, 67.3725 respectively. Which are correct results if we check manually.

    import cv2
    import numpy as np
    
    # Load the image in grayscale
    img = cv2.imread('/home/cvlab/Downloads/xy.jpg', cv2.IMREAD_GRAYSCALE)
    cv2.namedWindow('Image', cv2.WINDOW_NORMAL)
    
    # Apply median blur
    img = cv2.medianBlur(img, 5)
    cv2.imshow('Image', img)
    
    # Initialize lists to store counts
    cntsUpper = []
    cntsLower = []
    
    # Loop through columns
    for i in range(img.shape[1]):
        cntUpper = 0
        cntLower = 0
        for j in range(img.shape[0]):
            pixel_value = img[j, i]
            if 15 < pixel_value < 250:
                cntUpper += 1
            elif pixel_value < 15:
                cntLower += 1
    
        if cntUpper != 0:
            cntsUpper.append(cntUpper)
        if cntLower != 0:
            cntsLower.append(cntLower)
    
    # Calculate the average for lower counts
    if cntsLower:
        averageLower = sum(cntsLower) / len(cntsLower)
        print(f"Average Lower: {averageLower}")
    
    # Calculate the average for upper counts
    if cntsUpper:
        averageUpper = sum(cntsUpper) / len(cntsUpper)
        print(f"Average Upper: {averageUpper}")
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()