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

2024-04-18 06:57:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图根据图片中的一些物体的形状和颜色来检测它们

这是原始图像,我想找到两个粉红色的杯子(以绿色突出显示)

enter image description here

我使用了一个彩色遮罩来隔离两个杯子,结果非常好,正如你在这里看到的:

enter image description here

问题是可能还有其他颜色相似的物体也会被检测到,比如右下角的红色椅子

我可以更好地调整颜色遮罩的参数…例如,我可以更具体地隔离颜色,使用膨胀/腐蚀来减少噪声。但是仅仅依靠颜色是不理想的,而且很容易出错。例如,如果我只是轻轻转动椅子,椅子上的灯光就会改变,我会再次听到噪音

为了让一切变得更加坚固,我一直在尝试使用cv2.approxPolyDP的形状来进一步选择杯子,但我经常无法将杯子与嘈杂的区域分开。由颜色遮罩识别的杯子形状通常不是非常精确,因此近似多边形最多可以由10个部分组成,这使得将其与噪声分离是无用的

这是我正在使用的代码:

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()

因此,我的主要问题还是关于形状检测。我想知道我是否可以尝试一种不同的方法来更好地利用我正在寻找一种非常特殊的形状这一事实,也许可以使用cv2.approxPolyDP以外的东西。有什么建议吗


Tags: 颜色maskareacv2framecolorlow形状
1条回答
网友
1楼 · 发布于 2024-04-18 06:57:46

我检查了你的照片。这是我能在5分钟内做得最好的。多练习一点,就会有更好的结果

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)

结果是这样的:

enter image description here

相关问题 更多 >