-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path预处理.cpp
181 lines (163 loc) · 4.93 KB
/
预处理.cpp
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
174
175
176
177
178
179
180
181
/*
预处理。cpp
1.动态二值化,动态二值化会产生黑洞
2.滤波(可选)
3.去掉图像黑洞
调参:二值化blocksize,C
*/
#include "opencv2/opencv.hpp"
#include "符号阵列.h"
using namespace std;
using namespace cv;
/*
input_img:相机拍摄图像名称/路径
dst:二值化图像
*/
void preprocessing(String input_img, Mat& dstImg)
{
Mat srcImg; //原图
Mat binary_img;//二值化图
//Mat b2;
srcImg = imread(input_img, 0); //读入灰度图像
dstImg = Mat::zeros(srcImg.size(), CV_8UC1);
yx_adaptiveThreshold(srcImg, binary_img, 7, -3);//二值化
//threshold(srcImg, b2, 150,255, CV_THRESH_BINARY );
//imshow("only b", binary_img);
//imshow("固定阈值", b2);
RemoveSmallRegion(binary_img, dstImg, 10, 0, 0);//去黑点
RemoveSmallRegion(dstImg, dstImg, 10, 1, 0);//去白点
}
/*
function:图像中去除小区域,优化二值化后图像
para:
CheckMode: 0代表去除黑区域,1代表去除白区域;
NeihborMode:0代表4邻域,1代表8邻域;
AreaLimit:小区域面积上限
注意:dst必须是一个初始化后的Mat,大小不能为0
dst可以为src
*/
void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int CheckMode, int NeihborMode)
{
int RemoveCount = 0; //记录除去的个数
//记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查
Mat Pointlabel = Mat::zeros(Src.size(), CV_8UC1);
if (CheckMode == 1)
{
//cout << "Mode: 去除小区域. ";
for (int i = 0; i < Src.rows; ++i)
{
uchar* iData = Src.ptr<uchar>(i);
uchar* iLabel = Pointlabel.ptr<uchar>(i);
for (int j = 0; j < Src.cols; ++j)
{
if (iData[j] < 10)
{
iLabel[j] = 3;
}
}
}
}
else
{
//cout << "Mode: 去除孔洞. ";
for (int i = 0; i < Src.rows; ++i)
{
uchar* iData = Src.ptr<uchar>(i);
uchar* iLabel = Pointlabel.ptr<uchar>(i);
for (int j = 0; j < Src.cols; ++j)
{
if (iData[j] > 10)
{
iLabel[j] = 3;
}
}
}
}
vector<Point2i> NeihborPos; //记录邻域点位置
NeihborPos.push_back(Point2i(-1, 0));
NeihborPos.push_back(Point2i(1, 0));
NeihborPos.push_back(Point2i(0, -1));
NeihborPos.push_back(Point2i(0, 1));
if (NeihborMode == 1)
{
//cout << "Neighbor mode: 8邻域." << endl;
NeihborPos.push_back(Point2i(-1, -1));
NeihborPos.push_back(Point2i(-1, 1));
NeihborPos.push_back(Point2i(1, -1));
NeihborPos.push_back(Point2i(1, 1));
}
//else cout << "Neighbor mode: 4邻域." << endl;
int NeihborCount = 4 + 4 * NeihborMode;
int CurrX = 0, CurrY = 0;
//开始检测
for (int i = 0; i < Src.rows; ++i)
{
uchar* iLabel = Pointlabel.ptr<uchar>(i);
for (int j = 0; j < Src.cols; ++j)
{
if (iLabel[j] == 0)
{
//********开始该点处的检查**********
vector<Point2i> GrowBuffer; //堆栈,用于存储生长点
GrowBuffer.push_back(Point2i(j, i));
Pointlabel.at<uchar>(i, j) = 1;
int CheckResult = 0; //用于判断结果(是否超出大小),0为未超出,1为超出
for (int z = 0; z<GrowBuffer.size(); z++)
{
for (int q = 0; q<NeihborCount; q++) //检查四个邻域点
{
CurrX = GrowBuffer.at(z).x + NeihborPos.at(q).x;
CurrY = GrowBuffer.at(z).y + NeihborPos.at(q).y;
if (CurrX >= 0 && CurrX<Src.cols&&CurrY >= 0 && CurrY<Src.rows) //防止越界
{
if (Pointlabel.at<uchar>(CurrY, CurrX) == 0)
{
GrowBuffer.push_back(Point2i(CurrX, CurrY)); //邻域点加入buffer
Pointlabel.at<uchar>(CurrY, CurrX) = 1; //更新邻域点的检查标签,避免重复检查
}
}
}
}
if (GrowBuffer.size()>AreaLimit) CheckResult = 2; //判断结果(是否超出限定的大小),1为未超出,2为超出
else { CheckResult = 1; RemoveCount++; }
for (int z = 0; z<GrowBuffer.size(); z++) //更新Label记录
{
CurrX = GrowBuffer.at(z).x;
CurrY = GrowBuffer.at(z).y;
Pointlabel.at<uchar>(CurrY, CurrX) += CheckResult;
}
//********结束该点处的检查**********
}
}
}
CheckMode = 255 * (1 - CheckMode);
//开始反转面积过小的区域
for (int i = 0; i < Src.rows; ++i)
{
uchar* iData = Src.ptr<uchar>(i);
uchar* iDstData = Dst.ptr<uchar>(i);
uchar* iLabel = Pointlabel.ptr<uchar>(i);
for (int j = 0; j < Src.cols; ++j)
{
if (iLabel[j] == 2)
{
iDstData[j] = CheckMode;
}
else if (iLabel[j] == 3)
{
iDstData[j] = iData[j];
}
}
}
//cout << RemoveCount << " objects removed." << endl;
}
/*
blockSize:用来计算每个像素的阈值的邻域大小,如3,5,7等。
C:从adaptiveMethod选择的方法中计算出来的平均值或加权平均值减去的参数值,可以是正数或负数。
C为负数:C绝对值变大会减少图像白点
C为正数:C变大会减少图像黑点
*/
void yx_adaptiveThreshold(InputArray src, OutputArray dst, int blockSize, double C)
{
adaptiveThreshold(src, dst, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, blockSize, C);
}