简体   繁体   English

基于颜色python的对象上的边界框

[英]Bounding box on objects based on color python

I try to draw a bounding box on every object in this picture, i wrote this code from documentation 我尝试在这张图片中的每个对象上绘制一个边界框,我从文档中编写了这段代码

import cv2 as cv2
import os
import numpy as np


img = cv2.imread('1 (2).png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
ret,thresh = cv2.threshold(img,127,255,0)
im2,contours,hierarchy = cv2.findContours(thresh, 1, 2)
for item in range(len(contours)):
    cnt = contours[item]
    if len(cnt)>20:
        print(len(cnt))
        M = cv2.moments(cnt)
        cx = int(M['m10']/M['m00'])
        cy = int(M['m01']/M['m00'])
        x,y,w,h = cv2.boundingRect(cnt)
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
        cv2.imshow('image',img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

the result is only one object, 结果只有一个对象,
PIC1

when i change the value 127 in this line to 200 in this line ret,thresh = cv2.threshold(img,127,255,0) i got different object. 当我在这一行中将此行中的值127更改为200时ret,thresh = cv2.threshold(img,127,255,0)我得到了不同的对象。 PIC2

here's the original image 这是原始图像
原始图片

The question is how can i detect all objects once? 问题是如何一次检测所有对象?

The approach is fairly straightforward. 这种方法相当简单。 We begin by converting to HSV and grabbing only the hue channel. 我们首先转换为HSV并仅抓取色调通道。

image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
h,_,_ = cv2.split(image_hsv)

Next, we find the dominant hues -- first count the occurrences of each hue using numpy.bincount (we flatten the hue channel image to make it one-dimensional): 接下来,我们找到主导色调 - 首先使用numpy.bincount计算每个色调的出现次数(我们将色调通道图像flatten为一维):

bins = np.bincount(h.flatten())

And then find which ones are common enough using numpy.where : 然后使用numpy.where找到哪些是常见的:

MIN_PIXEL_CNT_PCT = (1.0/20.0)
peaks = np.where(bins > (h.size * MIN_PIXEL_CNT_PCT))[0]

Now that we've identified all the dominant hues, we can repeatedly process the image to find the areas correspond to each of them: 现在我们已经确定了所有主要色调,我们可以重复处理图像以找到与每个图像对应的区域:

for i, peak in enumerate(peaks):

We begin by creating a mask which selects all the pixels of this hue ( cv2.inRange , and then extracting the corresponding parts from the input BGR image ( cv2.bitwise_and . 我们首先创建一个遮罩,选择该色调的所有像素( cv2.inRange ,然后从输入BGR图像中提取相应的部分( cv2.bitwise_and

mask = cv2.inRange(h, peak, peak)
blob = cv2.bitwise_and(image, image, mask=mask)

Next, we find the contours ( cv2.findContours of all the continuous areas of this hue, so that we can process each of them individually 接下来,我们找到轮廓(此色调的所有连续区域的cv2.findContours ,以便我们可以单独处理它们中的每一个

_, contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

Now, for each of the identified continuous area 现在,为每个确定的连续区域

for j, contour in enumerate(contours):

We determine the bounding box ( cv2.boundingRect , and create a mask corresponding to just this contour by filling the contour polygon with white ( numpy.zeros_like and cv2.drawContours ) 我们确定边界框( cv2.boundingRect ,并通过用白色填充轮廓多边形来创建与此轮廓相对应的蒙版( numpy.zeros_likecv2.drawContours

bbox = cv2.boundingRect(contour)
contour_mask = np.zeros_like(mask)
cv2.drawContours(contour_mask, contours, j, 255, -1)

Then we can extra just the ROI corresponding to the bounding box 然后我们可以额外添加与边界框对应的ROI

region = blob.copy()[bbox[1]:bbox[1]+bbox[3],bbox[0]:bbox[0]+bbox[2]]
region_mask = contour_mask[bbox[1]:bbox[1]+bbox[3],bbox[0]:bbox[0]+bbox[2]]
region_masked = cv2.bitwise_and(region, region, mask=region_mask)

Or visualize ( cv2.rectangle the bounding box: 或者可视化( cv2.rectangle the bounding box:

result = cv2.bitwise_and(blob, blob, mask=contour_mask)
top_left, bottom_right = (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3])
cv2.rectangle(result, top_left, bottom_right, (255, 255, 255), 2)

Or do any other processing you want. 或者做你想要的任何其他处理。


Full Script 完整的脚本

import cv2
import numpy as np

# Minimum percentage of pixels of same hue to consider dominant colour
MIN_PIXEL_CNT_PCT = (1.0/20.0)

image = cv2.imread('colourblobs.png')
if image is None:
    print("Failed to load iamge.")
    exit(-1)

image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# We're only interested in the hue
h,_,_ = cv2.split(image_hsv)
# Let's count the number of occurrences of each hue
bins = np.bincount(h.flatten())
# And then find the dominant hues
peaks = np.where(bins > (h.size * MIN_PIXEL_CNT_PCT))[0]

# Now let's find the shape matching each dominant hue
for i, peak in enumerate(peaks):
    # First we create a mask selecting all the pixels of this hue
    mask = cv2.inRange(h, peak, peak)
    # And use it to extract the corresponding part of the original colour image
    blob = cv2.bitwise_and(image, image, mask=mask)

    _, contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    for j, contour in enumerate(contours):
        bbox = cv2.boundingRect(contour)
        # Create a mask for this contour
        contour_mask = np.zeros_like(mask)
        cv2.drawContours(contour_mask, contours, j, 255, -1)

        print "Found hue %d in region %s." % (peak, bbox)
        # Extract and save the area of the contour
        region = blob.copy()[bbox[1]:bbox[1]+bbox[3],bbox[0]:bbox[0]+bbox[2]]
        region_mask = contour_mask[bbox[1]:bbox[1]+bbox[3],bbox[0]:bbox[0]+bbox[2]]
        region_masked = cv2.bitwise_and(region, region, mask=region_mask)
        file_name_section = "colourblobs-%d-hue_%03d-region_%d-section.png" % (i, peak, j)
        cv2.imwrite(file_name_section, region_masked)
        print " * wrote '%s'" % file_name_section

        # Extract the pixels belonging to this contour
        result = cv2.bitwise_and(blob, blob, mask=contour_mask)
        # And draw a bounding box
        top_left, bottom_right = (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3])
        cv2.rectangle(result, top_left, bottom_right, (255, 255, 255), 2)
        file_name_bbox = "colourblobs-%d-hue_%03d-region_%d-bbox.png" % (i, peak, j)
        cv2.imwrite(file_name_bbox, result)
        print " * wrote '%s'" % file_name_bbox

Console Output 控制台输出

Found hue 32 in region (186, 184, 189, 122).
 * wrote 'colourblobs-0-hue_032-region_0-section.png'
 * wrote 'colourblobs-0-hue_032-region_0-bbox.png'
Found hue 71 in region (300, 197, 1, 1).
 * wrote 'colourblobs-1-hue_071-region_0-section.png'
 * wrote 'colourblobs-1-hue_071-region_0-bbox.png'
Found hue 71 in region (301, 195, 1, 1).
 * wrote 'colourblobs-1-hue_071-region_1-section.png'
 * wrote 'colourblobs-1-hue_071-region_1-bbox.png'
Found hue 71 in region (319, 190, 1, 1).
 * wrote 'colourblobs-1-hue_071-region_2-section.png'
 * wrote 'colourblobs-1-hue_071-region_2-bbox.png'
Found hue 71 in region (323, 176, 52, 14).
 * wrote 'colourblobs-1-hue_071-region_3-section.png'
 * wrote 'colourblobs-1-hue_071-region_3-bbox.png'
Found hue 71 in region (45, 10, 330, 381).
 * wrote 'colourblobs-1-hue_071-region_4-section.png'
 * wrote 'colourblobs-1-hue_071-region_4-bbox.png'
Found hue 109 in region (0, 0, 375, 500).
 * wrote 'colourblobs-2-hue_109-region_0-section.png'
 * wrote 'colourblobs-2-hue_109-region_0-bbox.png'
Found hue 166 in region (1, 397, 252, 103).
 * wrote 'colourblobs-3-hue_166-region_0-section.png'
 * wrote 'colourblobs-3-hue_166-region_0-bbox.png'

Example Output Images 示例输出图像

Yellow bounding box: 黄色边框:

Hue 32边界框

Yellow extracted region: 黄色提取区域:

Hue 32部分

Biggest green bounding box (there are several other small disjoint areas as well): 最大的绿色边框(还有其他几个小的不相交的区域):

Hue 71最大的边界框

...and the corresponding extracted region: ......和相应的提取区域:

顺化71最大的部分

First step is to understand what your algorithm is doing...specifically this function: ret,thresh = cv2.threshold(img,127,255,0) 第一步是了解你的算法在做什么...特别是这个函数: ret,thresh = cv2.threshold(img,127,255,0)

the value 127 is the greyscale value between 0 and 255. Threshold function changes pixel values below 127 to 0 and above 127 to 255 127是0到255之间的灰度值。阈值功能将像素值更改为127到0以及127到255以上

With reference to your coloured image, the greyscale output for both the green blob and yellow blob is above 127, so both of those are changed to 255, and hence both are captured by the findContours() method 参考彩色图像,绿色斑点和黄色斑点的灰度输出大于127,因此两者都更改为255,因此两者都由findContours()方法捕获

You can run imshow on thresh object to understand exactly what is going on. 您可以在thresh对象上运行imshow以准确了解正在发生的事情。

Now when you replace 127 with 200 , only the yellow blob has a greyscale value above 200, so only that blob is seen in the thresh Mat 现在当你用200替换127时,只有黄色斑点的灰度值高于200,所以在thresh Mat中只能看到那个斑点

To detect "all objects" at once, please experiment further with threshold method and study the thresh object using imshow 要一次检测“所有对象”,请进一步使用threshold方法进行实验,并使用imshow研究thresh对象

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

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