opencv-073-二值图像分析(缺陷检测二)

知识点

对于得到的刀片外接矩形,首先需要通过排序,确定他们的编号,然后根据模板进行相减得到与模板不同的区域,对这些区域进行形态学操作,去掉边缘细微差异,最终就得到了可以检出的缺陷或者划痕刀片。

代码(c++,python)

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
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void sort_box(vector<Rect> &boxes);

Mat get_template(Mat &binary, vector<Rect> &rects);

void detect_defects(Mat &binary, vector<Rect> &rects, Mat &tpl, vector<Rect> &defects);

/*
* 二值图像分析(缺陷检测二)
*/
int main() {
Mat src = imread("../images/ce_02.jpg");
if (src.empty()) {
cout << "could not load image.." << endl;
}
imshow("input", src);

// 二值图像
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

// 开操作,去掉一些小块
Mat se = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(binary, binary, MORPH_OPEN, se);

// 绘制轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
vector<Rect> rects;
findContours(binary.clone(), contours, hierarchy, RETR_LIST, CHAIN_APPROX_SIMPLE);
int height = src.rows;
for (size_t t = 0; t < contours.size(); t++) {
Rect rect = boundingRect(contours[t]);
double area = contourArea(contours[t]);
if (rect.height > (height / 2)) {
continue;
}
if (area < 150) {
continue;
}
rects.push_back(rect);
// 填充边缘,放大缺陷
drawContours(binary, contours, t, Scalar(0), 2, 8);
}

// 对外接矩形框排序
sort_box(rects);

// 获取模板
Mat tpl = get_template(binary, rects);

for (int i = 0; i < rects.size(); ++i) {
putText(src, format("num:%d", (i + 1)), Point(rects[i].x - 60, rects[i].y + 15),
FONT_HERSHEY_PLAIN, 1.0, Scalar(255, 0, 0), 1);
}

// 检测并标明结果
vector<Rect> defects;
detect_defects(binary, rects, tpl, defects);
for (int i = 0; i < defects.size(); ++i) {
rectangle(src, defects[i], Scalar(0, 0, 255));
putText(src, "bad", Point(defects[i].x, defects[i].y),
FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 1);
}

imshow("result", src);

waitKey(0);
return 0;
}

void detect_defects(Mat &binary, vector<Rect> &rects, Mat &tpl, vector<Rect> &defects) {
int height = tpl.rows;
int width = tpl.cols;
int index = 1;
int size = rects.size();
// 发现缺失
for (int i = 0; i < size; ++i) {
Mat roi = binary(rects[i]);
resize(roi, roi, tpl.size());
Mat mask;
subtract(tpl, roi, mask);
Mat se = getStructuringElement(MORPH_RECT, Size(5, 5));
morphologyEx(mask, mask, MORPH_OPEN, se);
threshold(mask, mask, 0, 255, THRESH_BINARY);
int count = 0;
for (int row = 0; row < height; ++row) {
for (int col = 0; col < width; ++col) {
int pv = mask.at<uchar>(row, col);
if (pv == 255) {
++count;
}
}
}
if (count > 0) {
defects.push_back(rects[i]);
}
}
}

Mat get_template(Mat &binary, vector<Rect> &rects) {
return binary(rects[0]);
}

void sort_box(vector<Rect> &boxes) {
int size = boxes.size();
for (int i = 0; i < size - 1; ++i) {
for (int j = i; j < size; ++j) {
if (boxes[j].y < boxes[i].y) {
Rect tmp = boxes[i];
boxes[i] = boxes[j];
boxes[j] = tmp;
}
}
}
}
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
import cv2 as cv
import numpy as np


def sort_boxes(rois):
for i in range(0, len(rois)-1, 1):
for j in range(i, len(rois), 1):
x, y, w, h = rois[j]
if y < rois[i][1]:
bx, by, bw, bh = rois[i]
rois[i] = [x, y, w, h]
rois[j] = [bx, by, bw, bh]
return rois;


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):
height, width = tpl.shape
index = 1
defect_rois = []
# 发现缺失
for x, y, w, h in boxes:
roi = binary[y:y + h, x:x + w]
roi = cv.resize(roi, (width, height))
mask = cv.subtract(tpl, roi)
se = cv.getStructuringElement(cv.MORPH_RECT, (5, 5), (-1, -1))
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, se)
ret, mask = cv.threshold(mask, 0, 255, cv.THRESH_BINARY)
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])
index += 1
return defect_rois


src = cv.imread("D:\code-workspace\Clion-workspace\learnOpencv\images\ce_02.jpg")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)

# 图像二值化
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)

se = cv.getStructuringElement(cv.MORPH_RECT, (3, 3), (-1, -1))
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, se)
cv.imshow("binary", binary)

# 轮廓提取
contours, hierarchy = cv.findContours(binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
height, width = src.shape[:2]
rects = []
for c in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[c])
area = cv.contourArea(contours[c])
if h > (height//2):
continue
if area < 150:
continue
rects.append([x, y, w, h])

# 排序轮廓
rects = sort_boxes(rects)
print(rects)
template = get_template(binary, rects);

# 填充边缘
for c in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[c])
area = cv.contourArea(contours[c])
if h > (height//2):
continue
if area < 150:
continue
cv.drawContours(binary, contours, c, (0), 2, 8)
cv.imshow("template", template)

# 检测缺陷
defect_boxes = detect_defect(binary, rects, template)
for dx, dy, dw, dh in defect_boxes:
cv.rectangle(src, (dx, dy), (dx + dw, dy + dh), (0, 0, 255), 1, 8, 0)
cv.putText(src, "bad", (dx, dy), cv.FONT_HERSHEY_PLAIN, 1.0, (0, 255, 0), 2)

index = 1
for dx, dy, dw, dh in rects:
cv.putText(src, "num:%d"%index, (dx-40, dy+15), cv.FONT_HERSHEY_PLAIN, 1.0, (255, 0, 0), 1)
index += 1

cv.imshow("result", src)
cv.imwrite("D:/binary2.png", src)

cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github