基于python-opencv实现木质工件的污渍和划痕识别和分类

缺陷识别
简介:
这个项目是我的本科毕业设计,主要针对传送带上的木质圆形工件的缺陷识别和分类,并且进行工件的计数和缺陷工件的计数。这里我主要是识别污渍和划痕

缺陷类型
污渍:

划痕:


最后的成果

 


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("此处缺陷污渍")
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
28
29
30
31
32
33
34
35
36
37
全部程序
主程序:
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()

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
工件对象:
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

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
缺陷对象:
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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
总结
做出这些东西,所有的灵感都是来自csdn上各种关于图像处理的文章。可能做得并不是很好,但是还是想分享出来,也许会帮到更多的人。
————————————————
版权声明:本文为CSDN博主「Pickle_泡菜君」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44736584/article/details/105737739

posted @ 2022-06-14 14:38  苍月代表我  阅读(637)  评论(0)    收藏  举报