瓶子篓错误点检测
这是最近在课程作业中做的小项目,放在这里和大家分享一下。
主要任务:
检测出瓶子篓中存在错误的地方(如:未摆放瓶子、瓶子带盖、瓶子横着放置、瓶子上放有塑料杯等)并将这些错误分别标识出来。
主要步骤:
1、透视变换 2、裁剪 3、自适应均衡化 4、阈值分割 5、腐蚀膨胀 6、寻找目标轮廓 7、画轮廓最小外接矩形 8、显示图像
1、导入功能包,定义相关函数
import numpy as np
from imutils.perspective import four_point_transform
import imutils
import cv2
def cv_show(name, img): cv2.imshow(name,img) cv2.waitKey(0) #cv2.destroyAllWindows()
def Get_Outline(input_dir): image = cv2.imread("Resources/bottle_crate_01.png") #读图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #原图转灰度图 blurred = cv2.GaussianBlur(gray, (5,5),0) #高斯模糊 edged = cv2.Canny(blurred,75,200) #canny边缘检测 return image,gray,blurred,edged
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2、透视变换
说明:需要检测的这一组图像中,感兴趣的是中间的部分,图像中的背景和篓子的外框都是需要去除的。而瓶子篓有的摆的比较正,有的存在一定倾斜角度,所以单纯使用裁剪工具并不能对所有的图像奏效,不具有普适性。因为篓子的外框比较好检测,所以可以使用透视变换,通过检测出篓子的外框轮廓,从而找到四个角点进行四点透视变换。效果如下图所示(左为原图,右为透视变换效果图)。
##透视变换
#找透视变换的轮廓
def Get_cnt(edged): cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE) cnts = cnts[1] if imutils.is_cv2() else cnts[0] docCnt =None if len(cnts) > 0: cnts =sorted(cnts,key=cv2.contourArea,reverse=True) for c in cnts: peri = cv2.arcLength(c,True) # 轮廓按大小降序排序 approx = cv2.approxPolyDP(c,0.02 * peri,True) # 获取近似的轮廓 if len(approx) ==4: # 近似轮廓有四个顶点 docCnt = approx break return docCnt
if __name__=="__main__": input_dir = "Resources/bottle_crate_06.png" image,gray,blurred,edged = Get_Outline(input_dir) docCnt = Get_cnt(edged) result_img = four_point_transform(image , docCnt.reshape(4,2)) # 对原始图像进行四点透视变换
cv_show('image', image)
#cv_show('gray', gray)
#cv_show('blurred', blurred)
#cv_show('edged', edged)
cv_show('result_img', result_img) #透视变换后的结果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
3、裁剪
说明:透视变换之后的图像中左右边缘仍有部分反光较严重的地方,会对后面的二值化及开运算处理产生影响,因此可以裁剪掉。效果如下图。
Cropped = result_img[10:375,25:560]
#print(Cropped.shape)
#cv_show('Cropped', Cropped)1
2
3
4、自适应均衡化
说明:由于整个图像光线较暗,对比度太低,所以需要均衡化处理,而普通的直方图均衡化会使得图片曝光过亮,局部细节丢失,因此选择自适应均衡化处理,效果如下(左边为原图,中间为自适应均衡化,右边为直方图均衡化)。
#自适应均衡化
Cropped_gray = cv2.cvtColor(Cropped, cv2.COLOR_BGR2GRAY) #转灰度图
clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
cll = clahe.apply(Cropped_gray)
cv_show('cll', cll)1
2
3
4
5
5、阈值分割
以图10为例
#二值化处理
rst,th = cv2.threshold(cll, 120, 255, cv2.THRESH_BINARY)
cv_show('th', th)1
2
3
6、腐蚀膨胀
#腐蚀
kernel=np.ones((8,8),np.uint8)
imgEroded=cv2.erode(th,kernel,iterations=1)
cv_show('imgEroded', imgEroded)
#膨胀
imgDialation=cv2.dilate(imgEroded,kernel,iterations=1)
cv_show('imgDialation', imgDialation)1
2
3
4
5
6
7
7、寻找并画出目标轮廓
说明:形态学处理完成后,设定参数值,进行目标寻找。(这里将参数像素和设定为35效果较好)
#找目标轮廓
(cnts,_) = cv2.findContours(imgDialation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#画轮廓
list=[]
imgDialation_RGB=cv2.cvtColor(imgDialation, cv2.COLOR_GRAY2BGR)
for cnt in cnts:
(x, y, w, h) = cv2.boundingRect(cnt)
print(x, y, w, h)
if w > 35: cv2.drawContours(imgDialation_RGB,cnt,-1,(0,0,255),2) isNG = True list.append(cnt)
a=len(list) #目标数量
print(a)1
2
3
4
5
6
7
8
9
10
11
12
13
14
说明:这一步效果并不是十分好,可以从图中看出,在进行形态学处理时有部分原本连通的区域被断开了,导致轮廓识别时被识成了两个甚至多个轮廓。
8、画轮廓最小外接矩形并在图上显示
说明:找出目标(即错误点)的轮廓后通过cv2.minAreaRect()函数可以找到轮廓的最小外接矩形,通过cv2.drawContours()函数将其画出。通过cv2.putText()函数可将文字信息在图上直观地表示出来。如果图像没有错误,则显示“Good”,如果发现错误,则显示"Not Good"。
#如果目标数量大于零(即有故障)
if a>0: cv_show('imgDialation_RGB', imgDialation_RGB) print("NOT GOOD") #Cropped_RGB = cv2.cvtColor(Cropped, cv2.COLOR_GRAY2BGR) # 画目标轮廓的最小外接矩形 for cnt in list: rect = cv2.minAreaRect(cnt) box = np.int0(cv2.boxPoints(rect)) img = cv2.drawContours(Cropped, [box], -1, (0, 255, 0), 3) cv2.putText(img, "Not Good", (40, 40), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 150, 0), 3) cv_show("Img", img) #cv2.imwrite("contoursImage2.jpg", image)
else: #无故障 cv2.putText(image, "Good", (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 150, 0), 5) cv_show("image", image) print("GOOD") #无故障1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
以上就是bottle_crate的检测实现过程,其中还有一些小问题有待改进。如果有更好的方案的欢迎留言~
文章来源: blog.csdn.net,作者:PURSUIT_0119,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_43544490/article/details/112801494