缺陷识别
简介:
这个项目是我的本科毕业设计,主要针对传送带上的木质圆形工件的缺陷识别和分类,并且进行工件的计数和缺陷工件的计数。这里我主要是识别污渍和划痕
缺陷类型
污渍:
划痕:
最后的成果
- sum:为工件的总个数
- scratch_num:为含有划痕工件的总个数
- blot_num:为含有污渍工件的总个数
- 黄颜色圈住的缺陷为划痕
- 蓝颜色圈住的缺陷为污渍
简单思路
- 通过边缘检测,得到每个工件的坐标,并计算出工件的中心来标记工件的ID
- 通过工件的每一帧位移量来确定是否为同一个工件
- 将每一个工件截取出来,进行缺陷的提取
- 将提取的缺陷进行直方图计算,通过直方图来值归一化,通过颜色值分布来分类缺陷
缺陷识别和分类
缺陷一:污渍的直方图
提取缺陷
缺陷处的直方图
提取缺陷
缺陷处的直方图
缺陷二:划痕的直方图
提取缺陷
缺陷处的直方图
提取缺陷
缺陷处的直方图
由上方缺陷的直方图值分析可得,污渍的颜色值主要分布在50左右,划痕的颜色值主要分布在100左右。因此通过颜色分布即可对对缺陷进行分类,将直方图归一化方便确定颜色的分布,代码如下
ret = img[y:y + h, x: x + w]
# 提取缺陷
gray = cv2.cvtColor(ret, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 135, 250, cv2.THRESH_BINARY_INV)[1]
contours, hierarchy =cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
mask = np.zeros(gray.shape).astype(gray.dtype)
cv2.fillPoly(mask, contours, (255, 255, 255))
result = cv2.bitwise_and(gray, mask)
# 直方图计算
hist = cv2.calcHist([result], [0], None, [255], [1, 256])
s = sum(hist)
# 归一化
for i in range(len(hist)):
if hist[i] > 0:
hist[i] = hist[i] / s
# 判断缺陷
hist_sum_scratch = 0
hist_sum_blot = 0
for i in range(90, 135):
hist_sum_scratch = hist_sum_scratch + hist[i]
for i in range(15, 90):
hist_sum_blot = hist_sum_blot + hist[i]
if hist_sum_scratch > 0.6:
d = defects.Defect(1, x, y, w, h)
self.defects.append(d)
self.state = 1
print("此处缺陷划痕")
if hist_sum_blot > 0.6:
d = defects.Defect(2, x, y, w, h)
self.defects.append(d)
self.state = 2
print("此处缺陷污渍")
全部程序
主程序:
import numpy as np
import cv2
import Products as product
# 加载视频
cap = cv2.VideoCapture("F:/FFOutput/8-1.mp4")
# 变量
font = cv2.FONT_HERSHEY_SIMPLEX
products = []
pid = 1
areaTh = 18000
# 获取图像width, height
width = cap.get(3)
height = cap.get(3)
while cap.isOpened():
ret, frame = cap.read()
try:
# 复制图片,用于绘制
img = frame.copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)[1]
except:
print("EOF")
break
# 边缘检测,识别工件
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > areaTh:
M = cv2.moments(cnt)
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
x, y, w, h = cv2.boundingRect(cnt)
new = True
if cx > 100:
for i in products:
if abs(cx - i.getX()) <= 25 and abs(cy - i.getY()) <= 25:
new = False
i.updateCoords(cx, cy, x, y, w, h)
if new:
p = product.Product(pid, cx, cy, x, y, w, h)
p.save_pic(frame)
products.append(p)
product.count = pid
defects = p.defect_detect()
pid += 1
cv2.circle(img, (cx, cy), 5, (0, 0, 255), -1)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
for i in products:
# 标记ID
if i.getX() <= 600:
cv2.putText(img, str(i.getId()), (i.getX(), i.getY()), font, 1.0, i.getRGB(), 1, cv2.LINE_AA)
# 绘制缺陷
for j in i.defects:
if j.getState() == 1:
img = cv2.rectangle(img, (i.getBoundX() + j.getX(), i.getBoundY() + j.getY()),
(i.getBoundX() + j.getX() + j.getW() + 5,
i.getBoundY() + j.getY() + j.getH() + 5),
(0, 255, 255),
1)
elif j.getState() == 2:
img = cv2.rectangle(img, (i.getBoundX() + j.getX(), i.getBoundY() + j.getY()),
(i.getBoundX() + j.getX() + j.getW() + 5,
i.getBoundY() + j.getY() + j.getH() + 5),
(255, 255, 0),
1)
# 绘制sum
cv2.putText(img, "sum:" + str(product.count), (10, 30), font, 0.7, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img, "scratch_sum:" + str(product.Product.scratch_sum), (10, 50), font, 0.7, (0, 255, 255), 1,
cv2.LINE_AA)
cv2.putText(img, "blot_sum:" + str(product.Product.blot_sum), (10, 70), font, 0.7, (255, 255, 0), 1,
cv2.LINE_AA)
cv2.imshow("test", img)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
工件对象:
from random import randint
import cv2
import numpy as np
import Defects as defects
from matplotlib import pyplot as plt
class Product:
scratch_sum = 0
blot_sum = 0
count = 0
def __init__(self, p, xi, yi, x, y, w, h):
# 工件ID
self.pid = p
# 中心坐标
self.centre_x = xi
self.centre_y = yi
# 边框
self.bound_x = x
self.bound_y = y
self.bound_w = w
self.bound_h = h
# 颜色
self.R = randint(0, 255)
self.G = randint(0, 255)
self.B = randint(0, 255)
# 运动轨迹
self.tracks = []
# 0代表正常,1代表工件存在划痕,2代表工件存在污渍
self.state = 0
self.sample = 0
# 储存缺陷对象
self.defects = []
# 获取ID
def getId(self):
return self.pid
def getBoundX(self):
return self.bound_x
def getBoundY(self):
return self.bound_y
def getBoundW(self):
return self.bound_w
def getBoundH(self):
return self.bound_h
def getX(self): # 获取中心x
return self.centre_x
def getY(self): # 获取中心y
return self.centre_y
# 更新位置
def updateCoords(self, xn, yn, x, y, w, h):
self.centre_x = xn
self.centre_y = yn
self.bound_x = x
self.bound_y = y
self.bound_w = w
self.bound_h = h
# 增加轨迹位置
self.tracks.append([self.centre_x, self.centre_y])
# 获取轨迹
def getTracks(self):
return self.tracks
# 获取标记颜色
def getRGB(self):
return self.R, self.G, self.B
# 保存
def save_pic(self, frame):
pic = frame[self.bound_y:self.bound_y + self.bound_h, self.bound_x:self.bound_x + self.bound_w]
self.sample = pic
# 改变图像大小
cv2.imwrite("F:/image" + str(self.pid) + ".jpg", pic)
# 缺陷识别和分类
def defect_detect(self):
gray = cv2.cvtColor(self.sample, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 135, 250, cv2.THRESH_BINARY)[1]
contour, hierar = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
img = self.sample.copy()
for cnt in contour:
area = cv2.contourArea(cnt)
if 100 < area <= 15000:
x, y, w, h = cv2.boundingRect(cnt)
ret = img[y:y + h, x: x + w]
# 提取缺陷
gray = cv2.cvtColor(ret, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 135, 250, cv2.THRESH_BINARY_INV)[1]
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
mask = np.zeros(gray.shape).astype(gray.dtype)
cv2.fillPoly(mask, contours, (255, 255, 255))
result = cv2.bitwise_and(gray, mask)
# 直方图计算
hist = cv2.calcHist([result], [0], None, [255], [1, 256])
s = sum(hist)
# 判断缺陷
for i in range(len(hist)):
if hist[i] > 0:
hist[i] = hist[i] / s
# 判断缺陷
hist_sum_scratch = 0
hist_sum_blot = 0
for i in range(90, 135):
hist_sum_scratch = hist_sum_scratch + hist[i]
for i in range(15, 90):
hist_sum_blot = hist_sum_blot + hist[i]
if hist_sum_scratch > 0.6:
d = defects.Defect(1, x, y, w, h)
self.defects.append(d)
self.state = 1
# print("此处缺陷划痕")
if hist_sum_blot > 0.6:
d = defects.Defect(2, x, y, w, h)
self.defects.append(d)
self.state = 2
# print("此处缺陷污渍")
if self.state == 1:
Product.scratch_sum = Product.scratch_sum + 1
elif self.state == 2:
Product.blot_sum = Product.blot_sum + 1
return self.defects
缺陷对象:
class Defect:
def __init__(self, state, x, y, w, h):
self.state = state
self.bound_x = x
self.bound_y = y
self.bound_w = w
self.bound_h = h
def getX(self):
return self.bound_x
def getY(self):
return self.bound_y
def getW(self):
return self.bound_w
def getH(self):
return self.bound_h
def getState(self):
return self.state
总结
做出这些东西,所有的灵感都是来自csdn上各种关于图像处理的文章。可能做得并不是很好,但是还是想分享出来,也许会帮到更多的人。