简体   繁体   English

Python opencv,基于颜色/形状的检测

[英]Python opencv, color/shape based detection

I'm trying to detect some objects in a picture based on their shape and color.我正在尝试根据它们的形状和颜色检测图片中的某些对象。

This is the original image, and I want to locate the two pink mugs (highlighted in green)这是原始图像,我想找到两个粉红色的杯子(以绿色突出显示)

在此处输入图像描述

I'm using a color mask to isolate the two mugs, and the result is pretty good, as you can see here:我正在使用颜色蒙版来隔离两个杯子,结果非常好,如您在此处看到的:

在此处输入图像描述

The problem is that there could be other objects with similar colors that get detected as well, as the red chair in the bottom right part.问题是可能还有其他具有类似 colors 的对象也被检测到,例如右下角的红色椅子。

I can tweak with the parameters for the color mask better...for example, I can isolate the color more specifically, use dilation/erosion to reduce noise.我可以更好地调整颜色蒙版的参数……例如,我可以更具体地隔离颜色,使用膨胀/侵蚀来减少噪音。 But relying only on colors is not ideal, and it's prone to errors.但是仅仅依靠colors并不理想,而且容易出错。 For example, if I simply turn the chair slightly, the lighting on it changes and I get noise again.例如,如果我只是稍微转动一下椅子,它上面的灯光就会改变,我又会听到噪音。

To make everything a little more robust, I've been trying to further select the mugs by using their shape with cv2.approxPolyDP, but I'm often unable to separate the mug from noisy regions.为了让一切变得更健壮,我一直在尝试通过使用 cv2.approxPolyDP 的形状来进一步 select 杯子,但我经常无法将杯子与嘈杂的区域分开。 The mug shape identified by the color mask is often not very precise, so the approximating polygon can be formed by up to 10 segments, which makes it useless to separate it from noise.由颜色掩码识别的杯子形状通常不是很精确,因此近似多边形最多可以由 10 段组成,这使得将其与噪声区分开来是无用的。

This is the code I'm using:这是我正在使用的代码:

import cv2
import numpy as np 


def main():
    cap = cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

    cv2.namedWindow("Color selection")
    cv2.createTrackbar("Low_H", "Color selection", 114, 255, nothing)
    cv2.createTrackbar("Low_S", "Color selection", 76, 255, nothing)
    cv2.createTrackbar("Low_V", "Color selection", 145, 255, nothing)
    cv2.createTrackbar("Up_H", "Color selection", 170, 255, nothing)
    cv2.createTrackbar("Up_S", "Color selection", 255, 255, nothing)
    cv2.createTrackbar("Up_V", "Color selection", 255, 255, nothing)
    cv2.createTrackbar("N_erosion", "Color selection", 4, 50, nothing)
    cv2.createTrackbar("epsilon", "Color selection", 2, 20, nothing)
    cv2.createTrackbar("Area_min", "Color selection", 52, 500, nothing)
    cv2.createTrackbar("Area_max", "Color selection", 1800, 4000, nothing)


    while True:
        ret, frame = cap.read()
        frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        frame_hsv_blur = cv2.GaussianBlur(frame_hsv, (7, 7), 0)

        ## parameters selection
        l_h = cv2.getTrackbarPos("Low_H", "Color selection")
        l_s = cv2.getTrackbarPos("Low_S", "Color selection")
        l_v = cv2.getTrackbarPos("Low_V", "Color selection")
        u_h = cv2.getTrackbarPos("Up_H", "Color selection")
        u_s = cv2.getTrackbarPos("Up_S", "Color selection")
        u_v = cv2.getTrackbarPos("Up_V", "Color selection")
        N_erode = cv2.getTrackbarPos("N_erosion", "Color selection")
        eps = cv2.getTrackbarPos("epsilon", "Color selection")/100
        area_min = cv2.getTrackbarPos("Area_min", "Color selection")
        area_max = cv2.getTrackbarPos("Area_max", "Color selection")
        N_erode = N_erode if N_erode>0 else 1

        lower_values = np.array([l_h, l_s, l_v])
        upper_values = np.array([u_h, u_s, u_v])
        mask = cv2.inRange(frame_hsv_blur, lower_values, upper_values)
        kernel = np.ones((N_erode,N_erode), np.uint8)
        mask = cv2.erode(mask, kernel)

        ## find contours in image based on color mask
        contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        for contour in contours:
            area = cv2.contourArea(contour)
            perimeter = cv2.arcLength(contour, True)
            approx = cv2.approxPolyDP(contour, eps*perimeter, True)
            x,y,w,h = cv2.boundingRect(contour)
            if (area_min < area < area_max) and (2<len(approx)):
                x_0 = int(x+w/2)
                y_0 = int(y+h/2)
                frame = cv2.putText(frame, str(len(approx)), (x,y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,0,0), thickness=3)
                frame = cv2.circle(frame, (x_0, y_0), 10, (255,255,50), -1)

        cv2.imshow("tracking", frame)
        cv2.imshow("mask", mask)


        key = cv2.waitKey(1)
        if key == ord('q'):
            break
        elif key == ord('s'):
            cv2.imwrite("saved_image.jpg", frame)

    cv2.destroyAllWindows()
    cap.release()


def nothing(x):
    pass


if __name__ == '__main__':
    main()

So, again, my main question regards the shape detection .所以,我的主要问题是关于形状检测 I was wondering if I could try a different approach to better exploit the fact that I'm looking for a very specific shape, maybe using something else than cv2.approxPolyDP.我想知道我是否可以尝试一种不同的方法来更好地利用我正在寻找一个非常具体的形状这一事实,也许使用 cv2.approxPolyDP 以外的其他东西。 Any suggestions?有什么建议么?

I checked your picture.我检查了你的照片。 This is what I could do best in 5 min.这是我在 5 分钟内能做的最好的事情。 practice a little more and the better result will show up.多练习一点,就会出现更好的结果。

import cv2
import numpy as np 
from google.colab.patches import cv2_imshow


img = cv2.imread("/content/JSjbB.png")
cv2_imshow(img)
img_output = img
cv2_imshow(img_output)
frame_hsv = cv2.cvtColor(img_output, cv2.COLOR_BGR2HSV)
frame_hsv_blur = cv2.GaussianBlur(frame_hsv, (7, 7), 0)
#print(frame_hsv_blur)
lower_values = np.array([130, 100,0])
upper_values = np.array([170,255, 255])
mask = cv2.inRange(frame_hsv_blur, lower_values, upper_values)
cv2_imshow(mask)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(mask,kernel,iterations = 3)
dilation = cv2.dilate(erosion,kernel,iterations = 3)
cv2_imshow(dilation)

The result is something like this:结果是这样的:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM