【问题标题】:Separate objects countours with OpenCV使用 OpenCV 分离对象轮廓
【发布时间】:2020-02-22 22:40:40
【问题描述】:

我一直在使用 OpenCV 来检测方形障碍物。到目前为止,这是我在应用过滤器和 canny 后得到的图像。

我试图识别的障碍是水平的,三个垂直的矩形是地板上的指导线。我的目标是只保留水平矩形,将其与其他矩形分开,但在应用 find Contours 后我只得到我是一个包含所有形状的对象。这是我一直在使用的代码,以便仅按其面积来确定最大的矩形:

# find the biggest countour (c) by the area
    if contours != 0:
        if not contours:
            print("Empty")

        else:
            bigone = max(contours, key=cv2.contourArea) if max else None
            area = cv2.contourArea(bigone)
            if area > 10000:
                x, y, w, h = cv2.boundingRect(bigone)
                cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2)
                cv2.putText(img, "Obstacle", (x+w/2, y-20),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)

                pts = np.array(
                    [[[x, y], [x+w, y], [x+w, y+h], [x, y+h]]], dtype=np.int32)
                cv2.fillPoly(mask, pts, (255, 255, 255))
                #values = img[np.where((mask == (255, 255, 255)).all(axis=2))]
                res = cv2.bitwise_and(img, mask)  # View only the obstacle
                obs_area = w*h
                print(obs_area)
                if obs_area <= 168000:

                    command_publisher.publish("GO")
                    cv2.putText(
                        img, "GO", (380, 400), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 255), 1)

                else:
                    command_publisher.publish("STOP")
                    cv2.putText(img, "STOP", (380, 400),
                                cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 255), 1)

                # show the output image
                cv2.imshow("Image", img)
                cv2.waitKey(1)

这是我得到的结果:

有没有办法通过某种过滤器或算法将我的障碍物与地板上的线条分开?

这是一个可以使用的示例图像:

【问题讨论】:

    标签: python opencv


    【解决方案1】:

    这是使用 Python/OpenCV 的一种方法。

     - Read the input
     - Convert to HSV and extract only the saturation channel (black/white/gray have zero saturation)
     - Threshold
     - Apply morphology open and close to remove the extranous white regions
     - Get the contour and approximate to simple polygon
     - Draw the polygon on the input
     - Save the results
    


    输入:

    import cv2
    import numpy as np
    
    # read image
    img = cv2.imread('board.png')
    
    # convert to HSV and extract saturation channel
    sat = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)[:,:,1]
    
    # threshold
    thresh = cv2.threshold(sat, 90, 255, 0)[1]
    
    # apply morphology close to fill interior regions in mask
    kernel = np.ones((7,7), np.uint8)
    morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
    kernel = np.ones((13,13), np.uint8)
    morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
    
    # get contours (presumably only 1) and fit to simple polygon (quadrilateral)
    cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
    c = cntrs[0]
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.05 * peri, True)
    
    # draw polygon on input
    result = img.copy()
    cv2.polylines(result, [np.int32(approx)], True, (0,0,255), 1, cv2.LINE_AA)
    
    
    # write result to disk
    cv2.imwrite("board_saturation.png", sat)
    cv2.imwrite("board_thresh.png", thresh)
    cv2.imwrite("board_morph.png", morph)
    cv2.imwrite("board_contour.png", result)
    
    # display it
    cv2.imshow("IMAGE", img)
    cv2.imshow("SAT", sat)
    cv2.imshow("THRESH", thresh)
    cv2.imshow("MORPH", morph)
    cv2.imshow("RESULT", result)
    cv2.waitKey(0)
    


    饱和度通道图:

    阈值图像:

    形态清洁图像:

    输入轮廓:

    【讨论】:

    【解决方案2】:

    在您的图像中,问题似乎是白色矩形。我的方法是检查每一行,如果行包含许多接近白色(255,255,255)的像素,则将行设为黑色。

    这是我的代码:

    import cv2
    import numpy as np
    import random as rng
    
    
    img=cv2.imread("/ur/image/directory/obstacle.png")
    height, width, channels = img.shape
    cv2.imshow('Source',img)
    
    # Check each line and eliminate white rectangles(if line consist white pixels more than limit)
    for x in range(0,height):
        white_counter = 0
        for y in range(0,width):
            if  img[x,y,0] >= 180 and img[x,y,1] >= 180 and img[x,y,2] >= 180: 
                white_counter = white_counter + 1
    
        if white_counter>10:
            for y in range(0,width):
                img[x,y,0] = 0
                img[x,y,1] = 0
                img[x,y,2] = 0
    
    cv2.imshow('Elimination White Rectangles', img)
    
    # Find contours and draw rectangle for each
    
    src_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    threshold = 300
    canny_output = cv2.Canny(src_gray, threshold, threshold * 2)
    contours, _ = cv2.findContours(canny_output, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    contours_poly = [None]*len(contours)
    boundRect = [None]*len(contours)
    for i, c in enumerate(contours):
            contours_poly[i] = cv2.approxPolyDP(c, 3, True)
            boundRect[i] = cv2.boundingRect(contours_poly[i])
    
    rng.seed(12345)
    drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
    
    for i in range(len(contours)):
            color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
            cv2.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \
              (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)
    
    cv2.imshow('Output', drawing)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    消除白色矩形:

    结果:

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-15
    • 2011-08-27
    • 2019-11-04
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    相关资源
    最近更新 更多