目录

  • 1. 基本思路
  • 2.代码
  • 3.局限性


1. 基本思路

1. 保证图片背景尽量为纯黑或纯白
为了数量检测的方便,将垃圾的背景设置为纯色,最好是纯黑色或纯白色,一会解释原因。

opencv 除法 opencv计数_opencv 除法


2. 将RGB图片转为灰度图

opencv 除法 opencv计数_计算机视觉_02


3. opencv找到能将灰度值最大程度分开的阈值ret

opencv的算法自动找到最合适的阈值ret,ret能将灰度图每个像素的灰度值最大限度的区分开。灰度图每个像素的灰度值为0(纯黑)到255(纯白),上面的灰度图中像素灰度值的分布如下所示。

opencv 除法 opencv计数_计算机视觉_03


可以看到opencv自动找到ret=92。

这里来说明两个问题:

(1)为什么要转为灰度图?

因为彩色图有RGB三个维度,而灰度图只有0(纯黑)-255(纯白)这一个维度,便于处理。

(2)为什么要保证背景尽量为纯黑或纯白?

因为在第三步找阈值ret时,要把灰度值的分布图最大程度的分开。背景颜色所占像素很多,如果背景为别的颜色,转为灰度值会位于分布图的中间,就会影响找到的阈值ret。(我们可以看到,在上面的分布图中大多数灰度值接近0,这是因为背景接近黑色,转换为灰度值会更接近0)

4. 二值化处理

灰度值小于ret的像素置为0(黑色),大于ret的像素值为255(白色),将上面的灰度图转换为黑白图,如下所示:

opencv 除法 opencv计数_opencv_04

5. 计算白色区域的个数

使用opencv算法对每个不相邻的白色区域像素值进行统计,同时过滤像素值较小的白色区域。(如某个白色区域只有20个像素值,则不大可能是一个物品,排除)对像素量超过1000的白色区域计数,即可得到图片中物体的数量。

还可以画出连通域:

opencv 除法 opencv计数_灰度值_05

2.代码

import cv2

# # 计算面积 去除面积小的 连通域
def Filter(contours):
    sum = 0
    a = []
    for i,area in enumerate(contours):
        if cv2.contourArea(area)>800:  
            a.append(contours[i])
            sum+=1
    return sum, a

if __name__ == '__main__':
    frame = cv2.imread("E:\\GarbageClassification\\1.png")   
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #将图片变为灰度图片
    ret2, thresh2 = cv2.threshold(gray,0,255,cv2.THRESH_OTSU)# 算法自动找出合适阈值ret2,将灰度图转换为黑白图,thresh2为返回的黑白图
    contours,hirearchy=cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 找出连通域
    sum, contours_1 = Filter(contours)
    img1=cv2.drawContours(frame,contours_1,-1,(0,0,255),3)

    # 所有操作结束后进行释放
    cv2.imshow("img1",gray)
    cv2.imshow("img2",thresh2)
    cv2.imshow("img3",img1)
    print(sum)
    if cv2.waitKey():
        cv2.destroyAllWindows()

3.局限性

这个思路很简单粗暴,但也存在一些局限性:

(1)对背景有要求,背景不能太乱,对环境较为敏感,尽量保证物品和背景颜色差别较大;

(2)物品最好不要反光,否则会检测不准;

(3)无法处理物品有重叠的情况,如果两个橙子挨在一起,就会检测成一个。