自动光学检测,目标分割和检测

Overview

在复习CookBook的闲暇,看了看OpenCV By Example, 里面的示例很不错,这里做下记录。此处实现了目标的背景去除,目标的分割和检测,以工厂螺母为例。就是下面的图啦。


Code

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173


//
// Created by shensir on 17-5-17.
//

#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

using namespace std;
using namespace cv;

// 光纹去除
Mat removeLight(Mat img, Mat pattern, int method){
Mat aux;
// 如果方法是归一化
if(method==1){
// 相除时需要将图像改为32位浮点型
Mat img32, pattern32;
img.convertTo(img32, CV_32F);
pattern.convertTo(pattern32, CV_32F);
// 图像相除模式
aux = 255*(1-(img32/pattern32));
// 换回8bit
aux.convertTo(aux, CV_8U);
}
else{
aux = pattern - img;
}
return aux;
}

// 估计背景图像,大尺寸核矩阵模糊
Mat calculateLightPattern(Mat img){
Mat pattern;
blur(img, pattern, Size(img.cols/3, img.rows/3));
return pattern;
}


// 先进行形态学操作[在背景色是核函数模糊得到的时候,很有必要],再二值化
Mat getBinary(Mat img_no_light, int method_light){
Mat img_thr;
if(method_light!=2){
threshold(img_no_light, img_thr, 30, 255, THRESH_BINARY);
} else{
threshold(img_no_light, img_thr, 140, 255, THRESH_BINARY_INV);
}

// 进行形态学操作去除边缘不规则噪点
cv::Mat closed;
cv::Mat element5(5 ,5, CV_8U, cv::Scalar(1));
cv::morphologyEx(img_thr, closed, // input and output
cv::MORPH_CLOSE, // operator code
element5); // structuring element

// Opening
cv::Mat opening;
cv::morphologyEx(closed, opening, // input and output
cv::MORPH_OPEN, // operator code
element5); // structuring element


imshow("img_thr_closed-opening", opening);

return opening;
}

static Scalar randomColor( RNG& rng )
{
int icolor = (unsigned) rng;
return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}

// 连通区域算法
void ConnectedComponents(Mat img){
// 使用连通区域分离符合要求部分图像Mat标签
Mat labels;
int num_objects = connectedComponents(img, labels);
// 检查检测到的目标数目
if(num_objects<2){
cout<<"No objects detected"<<endl;
return;
} else{
cout<<"Number of objects detected: "<< num_objects-1<<endl;
}
// 创建彩色目标的输出图像
Mat output=Mat::zeros(img.rows, img.cols, CV_8UC3);
RNG rng(0xFFFFFFFF);
for(int i=1; i<num_objects; i++){
Mat mask = labels==i;
output.setTo(randomColor(rng), mask);
}
imshow("Result", output);
}


// 连通区域算法
void ConnectedComponentsStats(Mat img){
// 连通区域统计信息
Mat labels, stats, centroids;
int num_objects = connectedComponentsWithStats(img, labels, stats, centroids);

// 检测物体数目判别
if(num_objects<2){
cout<<"No objects detedcted"<<endl;
return;
} else{
cout<<"Number of objects detected: "<<num_objects-1<<endl;
}
// 创建彩色对象的输出图像并显示区域
Mat output = Mat::zeros(img.rows, img.cols, CV_8UC3);
RNG rng(0xFFFFFFFF);

for(int i=1; i<num_objects; i++){
cout<<"Object "<<i<<" with pos: "<<centroids.at<Point2d>(i)
<<" with area "<<stats.at<int>(i, CC_STAT_AREA)<<endl;
Mat mask = labels==i;
output.setTo(randomColor(rng), mask);

// 使用区域绘制文本
stringstream ss;
ss<<"area: "<<stats.at<int>(i, CC_STAT_AREA);

putText(output, ss.str(), centroids.at<Point2d>(i), FONT_HERSHEY_SIMPLEX, 0.4, Scalar(255,255,255));
}
imshow("Result", output);
}


// 边缘检测算法
void FindContoursBasic(Mat img){
vector<vector<Point>> contours;
findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
Mat output = Mat::zeros(img.rows, img.cols, CV_8UC3);
// 检查检测到的对象的数目
if(contours.size() == 0){
cout<<"No objects detected"<<endl;
return;
} else{
cout<<"Number of objects detected: "<<contours.size()<<endl;
}

RNG rng(0xFFFFFFFF);
for(int i=0;i<contours.size();i++){
drawContours(output, contours, i, randomColor(rng));
}
imshow("Contours", output);
}



int main(){
Mat img = imread("/home/shensir/Documents/MyPrograming/Cpp/Clions/data/industry.pgm", IMREAD_GRAYSCALE);
imshow("Original Image", img);

Mat pattern = imread("/home/shensir/Documents/MyPrograming/Cpp/Clions/data/light.pgm",0);
imshow("Back", pattern);
// Mat pattern = calculateLightPattern(img);
Mat img_no_light = removeLight(img, pattern, 1);
imshow("removelight--minus", img_no_light);

Mat img_thr = getBinary(img_no_light,1);
// ConnectedComponents(img_thr);
ConnectedComponentsStats(img_thr);

FindContoursBasic(img_thr);
waitKey(0);
return 0;
}


输出:

Number of objects detected: 4
Object 1 with pos: [160.203, 143.822] with area 2315
Object 2 with pos: [263.535, 131.804] with area 1820
Object 3 with pos: [52.7045, 143.926] with area 1171
Object 4 with pos: [68.233, 202.819] with area 1618
Number of objects detected: 4

待改进的地方

在没有背景色图的时候,我们直接通过大尺寸核矩阵模糊化得到的效果很差,得到的objects大于50左右,后面自己加上了形态学的操作,降到了5个,但是还是多了一个。

本文标题:自动光学检测,目标分割和检测

文章作者:不秩稚童

发布时间:2017年05月18日 - 00:49:33

最后更新:2017年05月18日 - 01:02:55

原始链接:http://datahonor.com/2017/05/18/自动光学检测,目标分割和检测/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

击蒙御寇