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

Get the average color inside a contour with Open CV

所以我决定开始学习 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()

图像上的解决方案

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函数-> Cropping non rectangular contours但是它的算法有点慢(但没有限制)

如果你对非矩形轮廓感兴趣,你必须小心做均值,因为你需要掩码并且 mask/background 总是矩形所以你会在你不想要的东西上做均值

您可以先创建一个与输入图像具有相同尺寸并将像素值设置为零的新图像来创建蒙版。

然后在像素值为 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 颜色 space 并仅使用 H 通道来检测对象的颜色。