How to identify contours associated with my objects and find their geometric centroid

五迷三道 提交于 2019-12-11 05:36:50

问题


Problem Statement & Background Info:

EDIT: Constraints: The red coloring on the flange changes over time, so I'm not trying to use color recognition to identify my object at this moment unless it can be robust. Addition,ally external illumination my be a factor since this will be in an outdoor area in the future.

I have RGB-Depth camera and with it, I'm able to capture this scene. Where each pixel (x,y) has a depth value.

Applying a gradient magnitude filter to the depth map associated with my image I'm able to get the following edge map.

The gradient magnitudes are given the value of 0 if they had a magnitude that wasn't zero. Black (255) is for magnitude values associated with 0 (homogenous depth or a flat surface).

From this edge map I dialated the edges so picking up the contours would be easier.

Then I found the contours in the image and tried to plot just the 5 biggest contours.

PROBLEM

Is there a way to reliably find the contours associated with my objects (the red box and metal fixture) and then find their geometric centroid? I keep running into the issue that I can find contours in the image, but I have no way of selectively screening for the contours that are my objects and not noise.

I have provided the image I used for the image processing, but for some reason, OpenCV saves the image as a black image, and when you read it in using...

gray = cv2.imread('GRAYTEST.jpeg', cv2.IMREAD_GRAYSCALE)

it appears blue-ish and not a binary white/black image as I show. So sorry about that.

Here is the image:

Sorry, I don't know why it saved just as a black image, but if you read it in OpenCV it should show up with the same lines as "magnitude of gradients" plot.

MY CODE

    gray = cv2.imread('GRAYTEST.jpeg', cv2.IMREAD_GRAYSCALE)
    plt.imshow(gray)
    plt.title('gray start image')
    plt.show()

    blurred = cv2.bilateralFilter(gray, 8, 25, 25)  # blurr image while preserving edges
    kernel = np.ones((3, 3), np.uint8)  # define a kernel (block) to apply filters to

    dialated = cv2.dilate(blurred, kernel, iterations=1)
    plt.title('dialated')
    plt.imshow(dialated)
    plt.show()

    #Just performs a canny edge dectection on an image
    edges_empty = self.Commons.CannyE_Auto(dialated)  # Canny edge image for some sigma
    #makes an empty image using the same diemensions of the given image
    empty2 = self.Commons.make_empty(gray)

    _, contours, _ = cv2.findContours(edges_empty, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = sorted(contours, key=cv2.contourArea, reverse=True)[:5]  # get largest five contour area
    cv2.drawContours(empty2, cnts, -1, (255, 0, 0), thickness=1)

    plt.title('contours')
    plt.imshow(empty2)
    plt.show()

回答1:


  1. Instead of performing the blurring operation, dialation, canny edge detection on my already thresholded image, I just performed the contour detection on my original image.

  2. Then I was able to find a decent contour for the outline of my image by modifying findContour command.

    _, contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

replacing cv2.RETR_TREE with cv2.RETR_EXTERNAL I was able to get only the contours that were associated with an object's outline, rather than trying to get contours within the object. Switching to cv2.CHAIN_APPROX_NONE didn't show any noticeable improvements, but it may provide better contours for more complex geometries.

        for c in cnts:
        # compute the center of the contour
        M = cv2.moments(c)
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])

        # draw the contour and center of the shape on the image
        cv2.drawContours(empty2, [c], -1, (255, 0, 0), thickness=1)
        perimeter = np.around(cv2.arcLength(c, True), decimals=3)
        area = np.around(cv2.contourArea(c), decimals=3)

        cv2.circle(empty2, (cX, cY), 7, (255, 255, 255), -1)
        cv2.putText(empty2, "center", (cX - 20, cY - 20),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)

        cv2.putText(empty2, "P:{}".format(perimeter), (cX - 50, cY - 50),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)

        cv2.putText(empty2, "A:{}".format(area), (cX - 100, cY - 100),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)

Using the above code I was able to label centroid of each contour as well as information about each contours perimeter and area.

However, I was unable to perform a test that would select which contour was my desired contour. I have an idea to capture my object in a more ideal setting and find its centroid, perimeter, and associated area. This way when I find a new contour I can compare it with how close it is to my known values.

I think this method could work to remove contours that are too large or too small.

If anyone knows of a better solution that would be fantastic!



来源:https://stackoverflow.com/questions/54849567/how-to-identify-contours-associated-with-my-objects-and-find-their-geometric-cen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!