0

I am trying to find centers of 2 squares in the same image which looks as follows:

Input Image

I am able to detect the lines that make up the square. My output looks as follows:

Square image

As documented here to find the center of a polygon, I used moments to find center. Here is what I did.

import cv2
import numpy as np

img = cv2.imread('images/sq.png', 0)
gray = img

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)
ret,thresh = cv2.threshold(blur_gray,100,255,0)

low_threshold = 50
high_threshold = 150
edges = cv2.Canny(thresh, low_threshold, high_threshold)

rho = 1  # distance resolution in pixels of the Hough grid
theta = np.pi / 180  # angular resolution in radians of the Hough grid
threshold = 3  # minimum number of votes (intersections in Hough grid cell)
min_line_length = 50  # minimum number of pixels making up a line
max_line_gap = 20 # maximum gap in pixels between connectable line segments
line_image = np.copy(img) * 0  # creating a blank to draw lines on

# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line segments
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
                    min_line_length, max_line_gap)

for line in lines:
    for x1,y1,x2,y2 in line:
        cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),2)
        print("x1 {} y1 {} x2 {} y2 {}".format(x1,y1,x2,y2))

lines_edges = cv2.addWeighted(img, 0.5, line_image, 1, 0)

line_image_gray = cv2.cvtColor(line_image, cv2.COLOR_RGB2GRAY)

M = cv2.moments(line_image_gray)

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

cv2.circle(lines_edges, (cx, cy), 5, (0, 0, 255), 1)

cv2.imshow("res", lines_edges)
cv2.imshow("line_image", line_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

But this finds the center between 2 detected squares. How could I find the centers of each square while only using Hough methods?

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Sophia
  • 367
  • 1
  • 8
  • 14
  • 2
    Is this image a stand-in for a more complex and/or noisy image? For this image, detecting edges and lines and all that is total overkill. It's trivial to detect the two dark/colorful objects against the light-colored background. Then you apply connected component analysis (labeling) and compute the moments for each label. – Cris Luengo Jan 28 '19 at 23:00
  • @CrisLuengo Another very easy method would be to find contours with opencv, but as she mentioned in her [previous question](https://stackoverflow.com/questions/54388832/calculating-center-of-an-object-in-an-image), she explicitly wants to find centers by detecting lines if I understood her correctly. I think this should be added to this question, too. – user8408080 Jan 29 '19 at 01:31
  • @CrisLuengo Yes there are images including a triangle, pentagon, square. I do not want to use connectedComponents method by opencv because it uses findContours internally. How could I approach this otherwise? – Sophia Jan 29 '19 at 05:42
  • Connected component labelling is not related to contour finding. If the OpenCV's connected component labelling uses `findContours` internally, it is a very weird implementation. – Cris Luengo Jan 29 '19 at 06:22
  • @CrisLuengo I think I am wrong on findContours part, but cannot use any method like `connectedComponents` that acts as a substitute to Hough methods available with OpenCV. – Sophia Jan 29 '19 at 06:45
  • @user8408080 Have mentioned this. I think one way could be to detect the colors enclosed by the structure detected by the houghlinesP, but not sure how to do this. – Sophia Jan 29 '19 at 13:44
  • Are you saying that you have to use the Hough transform? That seems like a misguided requirement. Hough is the wrong approach to solve this problem. – Cris Luengo Jan 29 '19 at 14:29
  • @CrisLuengo Yes. I know that sounds weird given the plenty of techniques already available but need to use HoughTools. HoughLinesP can detect line segments and by tuning minLineLength and maxLineGap we can detect the enclosures. Once the enclosures are detected, we could take each enclosure and find the midpoint by calculating Moments for each enclosure. But I am not sure how could I separate one enclosure from another. – Sophia Jan 29 '19 at 14:44

2 Answers2

0

You could use this method combined with the following code to find which lines are part of the same square:

How can I check if two segments intersect?

Where 'lines' is a list of the recognized lines, and intersects(line1, line2) is a function using the process in the above link

squares = [[lines(1)]]    

for line1 in lines:
    for square in squares:
        for line2 in square:
            if line1 != line2:
                if intersects(line1, line2):
                    square.append(line1)
                else:
                    squares.append([line1])

This gives you 'squares' that contain the lines that are a part of it. You could then use the moment function on each individually.

Reagan Wiggs
  • 123
  • 1
  • 8
0

Given that you have a requirement to use the Hough transform, I suggest you prepare the image better for it. The Canny edge detector will detect the inner and outer edges of the black line here, leading to two pairs of lines detected by Hough.

Instead, follow a procedure like this:

  • Find all black (or nearly-black) pixels. For example pixels where all three RGB components are below 50. This will return the squares by themselves.

  • Apply a morphological thinning (or a skeleton) to turn this into a 1-pixel thick outline of the squares.

  • Apply the Hough transform on the result, and detect line segments.

Proper pre-processing makes the Hough transform easier to set up, as there will be a larger range of parameters that yields the correct results.

Next, find segments that start or end at the same pixel, with a little bit of tolerance (i.e. start or end points are within a few pixels of each other), to determine which of the lines belong together in the same shape.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Could k-means be used here? Came across: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html – Sophia Jan 29 '19 at 15:27
  • @Sophia: Sure, if you know in advance that there are two shapes, and they’re both compact, then k-means in the end points should do the trick. – Cris Luengo Jan 29 '19 at 15:34