Search code examples
pythonopencvcomputer-visionhough-transform

Calculating center of an object in an image


I was reading this post to calculate the center of an image using OpenCV which uses Moments. But I am trying to calculate the center of an object I detected using HoughLinesP. Is there a way with OpenCV I could do this?

Here is the image for which I am trying to calculate the centers.

enter image description here

The line segments were found and the output image looks like:

enter image description here

import cv2
import numpy as np
import math

img = cv2.imread("./images/octa.jpg")

b,g,r = cv2.split(img)

smoothed = cv2.GaussianBlur(g, (3,3), 0)

edges = cv2.Canny(smoothed, 15, 60, apertureSize = 3)

lines = cv2.HoughLinesP(edges,1,np.pi/180,35, 30, 20)


print("length of lines detected ", lines.shape)


for line in lines:
        for x1,y1,x2,y2 in line:
          cv2.line(img,(x1,y1),(x2,y2),(255,0,0),2)
          print("x1,y1", x1,",",y1, " --- ", "x2,y2", x2,",",y2)



cv2.imshow('detected',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Using the coordinates how could I calculate the center of this image? How could I use Moments here?

One constraint I have is that I cannot use Contour methods included with OpenCV.


Solution

  • The following code was used with cv2 version of 3.3.1.

    I closely followed the opencv docs and it worked fine.

    import cv2
    
    img = cv2.imread("octa.jpg", 0)
    ret,thresh = cv2.threshold(img,100,255,0)
    im2, contours, hierachy = cv2.findContours(thresh, 1, 2)
    cnt = contours[0]
    
    M = cv2.moments(cnt)
    
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])
    
    im2 = cv2.cvtColor(im2, cv2.COLOR_GRAY2RGB)
    
    cv2.polylines(im2, cnt, True, (0, 0, 255), 2)
    
    cv2.circle(im2, (cx, cy), 5, (0, 0, 255), 1)
    
    cv2.imshow("res", im2)
    

    Two notes:

    • you need to add the argument 0 to imread otherwise the contour finding would not work
    • I set the threshold just a little bit lower, so only the contours of the octagon were found

    Result:

    result

    If you use a different version of cv2, you can just change the docs to your version; the documentation is really good.

    You also may want to blur your image a bit or do some other preprocessing, but in this case, there was no need for it.

    EDIT Without contour:

    I took the helpful comments from this post and tinkered around a bit. This does not use contours. It finds lines and uses them to find the center

    import cv2
    import numpy as np
    
    mg = cv2.imread('octa.jpg')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    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 = 15  # minimum number of votes (intersections in Hough grid cell)
    min_line_length = 50  # minimum number of pixels making up a line
    max_line_gap = 50  # 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)
    
    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)
    

    Result: enter image description here Found lines are drawn in blue; the center in red