今天来一个缺陷检测的实例,如下是原图,第二个和第三个黑色部件有缺陷
思路:
①提取OK部件轮廓做model
②遍历部件轮廓,做差分,形态学处理
③结果判断绘制
上代码(含注释):
import cv2
import numpy as np
# 获取模板ROI
def get_template(binary, boxes):
x, y, w, h = boxes[0]
roi = binary[y:y+h, x:x+w]
return roi
def detect_defect(binary, boxes, tpl):
global src
height, width = tpl.shape
index = 1
defect_rois = []
# 发现缺失
for x, y, w, h in boxes:
roi = binary[y:y + h, x:x + w]
roi = cv2.resize(roi, (width, height))
mask = cv2.subtract(tpl, roi)
se = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5), (-1, -1))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, se)
ret, mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
mask, contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
color_mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
cv2.drawContours(color_mask, contours, -1, (0, 255, 255), -1, 8)
mask_roi = src[y:y + height, x:x + width]
cv2.bitwise_or(color_mask, mask_roi, mask_roi, mask = mask)
count = 0
for row in range(height):
for col in range(width):
pv = mask[row, col]
if pv == 255:
count += 1
if count > 0:
defect_rois.append([x, y, w, h])
else:
cv2.rectangle(src, (x, y), (x+w, y+h), (0, 255, 0), 2, 8, 0)
cv2.putText(src, "OK", (x, y - 2), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imwrite("mask%d.png"%index, mask)
index += 1
return defect_rois
global src
src = cv2.imread("1.jpg")
cv2.imshow("input", src)
# 图像二值化
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
# 形态学开运算
se = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3), (-1, -1))
binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, se)
cv2.imshow("binary", binary)
# 轮廓提取
out, contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
height, width = src.shape[:2]
rects = []
# 轮廓筛选
for c in range(len(contours)):
# 轮廓外接矩形
x, y, w, h = cv2.boundingRect(contours[c])
# 轮廓面积
area = cv2.contourArea(contours[c])
if h > (height//2):
continue
if area < 150:
continue
rects.append([x, y, w, h])
# 排序轮廓(按照rect中y值排序也就是纵坐标从小到大)
rects = sorted(rects, key = lambda x:x[1])
for i in range(len(rects)):
print(rects[i])
# 获取模板ROI
template = get_template(binary, rects)
cv2.imshow("template", template)
# 填充边缘
for c in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[c])
area = cv2.contourArea(contours[c])
if h > (height//2):
continue
if area < 150:
continue
cv2.drawContours(binary, contours, c, (0), 2, 8)
# 检测缺陷
defect_boxes = detect_defect(binary, rects, template)
for dx, dy, dw, dh in defect_boxes:
cv2.rectangle(src, (dx, dy), (dx + dw, dy + dh), (0, 0, 255), 2, 8, 0)
cv2.putText(src, "NG", (dx, dy-2), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
index = 1
for dx, dy, dw, dh in rects:
cv2.putText(src, "No.%d"%index, (dx-60, dy+30), cv2.FONT_HERSHEY_SIMPLEX, .7, (255, 0, 255), 2)
index += 1
cv2.imshow("result", src)
cv2.imwrite("binary2.png", src)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中76,77行说明:
# 排序轮廓(按照rect中y值排序也就是纵坐标从小到大)
rects = sorted(rects, key = lambda x:x[1]
最终检测效果(红色标注NG部件,黄色标注缺陷点):
文章来源:OpenCV与AI深度学习 ,作者Color Space