目录
- 1. 基本思路
- 2.代码
- 3.局限性
1. 基本思路
1. 保证图片背景尽量为纯黑或纯白
为了数量检测的方便,将垃圾的背景设置为纯色,最好是纯黑色或纯白色,一会解释原因。
2. 将RGB图片转为灰度图
3. opencv找到能将灰度值最大程度分开的阈值ret
opencv的算法自动找到最合适的阈值ret,ret能将灰度图每个像素的灰度值最大限度的区分开。灰度图每个像素的灰度值为0(纯黑)到255(纯白),上面的灰度图中像素灰度值的分布如下所示。
可以看到opencv自动找到ret=92。
这里来说明两个问题:
(1)为什么要转为灰度图?
因为彩色图有RGB三个维度,而灰度图只有0(纯黑)-255(纯白)这一个维度,便于处理。
(2)为什么要保证背景尽量为纯黑或纯白?
因为在第三步找阈值ret时,要把灰度值的分布图最大程度的分开。背景颜色所占像素很多,如果背景为别的颜色,转为灰度值会位于分布图的中间,就会影响找到的阈值ret。(我们可以看到,在上面的分布图中大多数灰度值接近0,这是因为背景接近黑色,转换为灰度值会更接近0)
4. 二值化处理
灰度值小于ret的像素置为0(黑色),大于ret的像素值为255(白色),将上面的灰度图转换为黑白图,如下所示:
5. 计算白色区域的个数
使用opencv算法对每个不相邻的白色区域像素值进行统计,同时过滤像素值较小的白色区域。(如某个白色区域只有20个像素值,则不大可能是一个物品,排除)对像素量超过1000的白色区域计数,即可得到图片中物体的数量。
还可以画出连通域:
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)无法处理物品有重叠的情况,如果两个橙子挨在一起,就会检测成一个。