使用Open CV获取轮廓内的平均颜色

9

所以我决定开始学习Open CV和Python!

我的第一个项目是检测相对静止背景上的移动物体,然后检测它们的平均颜色以进行分类。至少有10个物体需要检测,我正在处理一段彩色视频。

到目前为止,我已经成功去除了背景,识别出了轮廓(可选地获取每个轮廓的中心),但现在我正在努力获取每个轮廓内的平均颜色。虽然有些关于这种问题的主题,但大多数都是用C语言编写的。显然我可以使用cv.mean(),但我无法得到一个有效的掩码来传递给这个函数。我想这并不难,但我卡在那里了......干杯!

import numpy as np
import cv2

video_path = 'test.h264'

cap = cv2.VideoCapture(video_path)
fgbg = cv2.createBackgroundSubtractorMOG2()


while (cap.isOpened):

    ret, frame = cap.read()
    if ret==True:
        fgmask = fgbg.apply(frame)
        (contours, hierarchy) = cv2.findContours(fgmask, cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

        for c in contours:
            if cv2.contourArea(c) > 2000:
                cv2.drawContours(frame, c, -1, (255,0,0), 3)
        cv2.imshow('foreground and background',fgmask)
        cv2.imshow('rgb',frame)

    key = cv2.waitKey(1) & 0xFF

    if key == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

请详细说明一下。您所指的“平均颜色”是什么意思?您希望如何对它们进行“排序”?您正在处理什么样的有色视频,其中至少有10个要检测的对象。 - Employee
我正在开发一台颜色分选机。每个轮廓都是需要分类的对象。我的目标是识别出所有白色物体(或任何其他颜色),并通过机械臂等方式命令GPIO(我的树莓派)将它们从流程中移除。 - fab
2个回答

22

你可以通过首先创建一个与输入图像具有相同尺寸且像素值为零的新图像来创建掩码。

然后,使用像素值为255在此图像上绘制轮廓。生成的图像可用作掩码。

mask = np.zeros(frame.shape, np.uint8)
cv2.drawContours(mask, c, -1, 255, -1)

接着可以将mask作为参数传入cv.mean函数中,例如:

mean = cv.mean(frame, mask=mask)

只需警惕一点,RGB颜色的平均值并不总是有意义的。也许尝试将其转换为HSV颜色空间,并仅使用H通道来检测对象的颜色。


5

图像解决方案

1)找到轮廓(在这种情况下是矩形,不是矩形的轮廓要难得多)

2)找到轮廓的坐标

3)从轮廓处裁剪图像

4)对各个通道求和并将它们除以其中的像素数(或使用平均函数)

import numpy as np
import cv2
img = cv2.imread('my_image.jpg',1)
cp = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(cp,150,255,0)
cv2.imshow('img',thresh) 
cv2.waitKey(0)
im2,contours,hierarchy = cv2.findContours(thresh.astype(np.uint8), 1, 2)
cnts = contours
for cnt in cnts:
    if cv2.contourArea(cnt) >800: # filter small contours
        x,y,w,h = cv2.boundingRect(cnt) # offsets - with this you get 'mask'
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
        cv2.imshow('cutted contour',img[y:y+h,x:x+w])
        print('Average color (BGR): ',np.array(cv2.mean(img[y:y+h,x:x+w])).astype(np.uint8))
        cv2.waitKey(0)
cv2.imshow('img',img) 
cv2.waitKey(0)
cv2.destroyAllWindows()

为了去除噪点,您可以只取轮廓中心,并取较小的矩形进行检查。
对于非矩形轮廓,请查看cv2.fillPoly函数 -> 裁剪非矩形轮廓。但这是一个有点慢的算法(但没有限制)。
如果您对非矩形轮廓感兴趣,需要注意进行平均值处理,因为您将需要蒙版,而蒙版/背景始终是矩形的,因此您将在不想要的地方进行平均值处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接