各位用户为了找寻关于使用OpenCV去除面积较小的连通域的资料费劲了很多周折。这里教程网为您整理了关于使用OpenCV去除面积较小的连通域的相关资料,仅供查阅,以下为您介绍关于使用OpenCV去除面积较小的连通域的详细内容
这是后期补充的部分,和前期的代码不太一样
效果图
源代码
? 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/
/
测试
void CCutImageVS2013Dlg::OnBnClickedTestButton1()
{
vector<vector<Point> > contours;
/
/
轮廓数组
vector<Point2d> centers;
/
/
轮廓质心坐标
vector<vector<Point> >::iterator itr;
/
/
轮廓迭代器
vector<Point2d>::iterator itrc;
/
/
质心坐标迭代器
vector<vector<Point> > con;
/
/
当前轮廓
double area;
double minarea
=
1000
;
double maxarea
=
0
;
Moments mom;
/
/
轮廓矩
Mat image, gray, edge, dst;
image
=
imread(
"D:66.png"
);
cvtColor(image, gray, COLOR_BGR2GRAY);
Mat rgbImg(gray.size(), CV_8UC3);
/
/
创建三通道图
blur(gray, edge, Size(
3
,
3
));
/
/
模糊去噪
threshold(edge, edge,
200
,
255
, THRESH_BINARY_INV);
/
/
二值化处理,黑底白字
/
/
-
-
-
-
-
-
-
-
去除较小轮廓,并寻找最大轮廓
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
findContours(edge, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
/
/
寻找轮廓
itr
=
contours.begin();
/
/
使用迭代器去除噪声轮廓
while
(itr !
=
contours.end())
{
area
=
contourArea(
*
itr);
/
/
获得轮廓面积
if
(area<minarea)
/
/
删除较小面积的轮廓
{
itr
=
contours.erase(itr);
/
/
itr一旦erase,需要重新赋值
}
else
{
itr
+
+
;
}
if
(area>maxarea)
/
/
寻找最大轮廓
{
maxarea
=
area;
}
}
dst
=
Mat::zeros(image.rows, image.cols, CV_8UC3);
/
*
绘制连通区域轮廓,计算质心坐标
*
/
Point2d center;
itr
=
contours.begin();
while
(itr !
=
contours.end())
{
area
=
contourArea(
*
itr);
con.push_back(
*
itr);
/
/
获取当前轮廓
if
(area
=
=
maxarea)
{
vector<Rect> boundRect(
1
);
/
/
定义外接矩形集合
boundRect[
0
]
=
boundingRect(Mat(
*
itr));
cvtColor(gray, rgbImg, COLOR_GRAY2BGR);
Rect select;
select.x
=
boundRect[
0
].x;
select.y
=
boundRect[
0
].y;
select.width
=
boundRect[
0
].width;
select.height
=
boundRect[
0
].height;
rectangle(rgbImg, select, Scalar(
0
,
255
,
0
),
3
,
2
);
/
/
用矩形画矩形窗
drawContours(dst, con,
-
1
, Scalar(
0
,
0
,
255
),
2
);
/
/
最大面积红色绘制
}
else
drawContours(dst, con,
-
1
, Scalar(
255
,
0
,
0
),
2
);
/
/
其它面积蓝色绘制
con.pop_back();
/
/
计算质心
mom
=
moments(
*
itr);
center.x
=
(
int
)(mom.m10
/
mom.m00);
center.y
=
(
int
)(mom.m01
/
mom.m00);
centers.push_back(center);
itr
+
+
;
}
imshow(
"rgbImg"
, rgbImg);
/
/
imshow(
"gray"
, gray);
/
/
imshow(
"edge"
, edge);
imshow(
"origin"
, image);
imshow(
"connected_region"
, dst);
waitKey(
0
);
return
;
}
前期做的,方法可能不太一样
一,先看效果图
原图
处理前后图
二,实现源代码
? 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/
/
=
=
=
=
=
=
=
函数实现
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
void RemoveSmallRegion(Mat &Src, Mat &Dst,
int
AreaLimit,
int
CheckMode,
int
NeihborMode)
{
int
RemoveCount
=
0
;
/
/
新建一幅标签图像初始化为
0
像素点,为了记录每个像素点检验状态的标签,
0
代表未检查,
1
代表正在检查,
2
代表检查不合格(需要反转颜色),
3
代表检查合格或不需检查
/
/
初始化的图像全部为
0
,未检查
Mat PointLabel
=
Mat::zeros(Src.size(), CV_8UC1);
if
(CheckMode
=
=
1
)
/
/
去除小连通区域的白色点
{
/
/
cout <<
"去除小连通域."
;
for
(
int
i
=
0
; i < Src.rows; i
+
+
)
{
for
(
int
j
=
0
; j < Src.cols; j
+
+
)
{
if
(Src.at<uchar>(i, j) <
10
)
{
PointLabel.at<uchar>(i, j)
=
3
;
/
/
将背景黑色点标记为合格,像素为
3
}
}
}
}
else
/
/
去除孔洞,黑色点像素
{
/
/
cout <<
"去除孔洞"
;
for
(
int
i
=
0
; i < Src.rows; i
+
+
)
{
for
(
int
j
=
0
; j < Src.cols; j
+
+
)
{
if
(Src.at<uchar>(i, j) >
10
)
{
PointLabel.at<uchar>(i, j)
=
3
;
/
/
如果原图是白色区域,标记为合格,像素为
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
int
a
=
0
;
/
/
cout <<
"Neighbor mode: 4邻域."
<< endl;
int
NeihborCount
=
4
+
4
*
NeihborMode;
int
CurrX
=
0
, CurrY
=
0
;
/
/
开始检测
for
(
int
i
=
0
; i < Src.rows; i
+
+
)
{
for
(
int
j
=
0
; j < Src.cols; j
+
+
)
{
if
(PointLabel.at<uchar>(i, j)
=
=
0
)
/
/
标签图像像素点为
0
,表示还未检查的不合格点
{
/
/
开始检查
vector<Point2i>GrowBuffer;
/
/
记录检查像素点的个数
GrowBuffer.push_back(Point2i(j, i));
PointLabel.at<uchar>(i, j)
=
1
;
/
/
标记为正在检查
int
CheckResult
=
0
;
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)
/
/
判断结果(是否超出限定的大小),
1
为未超出,
2
为超出
CheckResult
=
2
;
else
{
CheckResult
=
1
;
RemoveCount
+
+
;
/
/
记录有多少区域被去除
}
for
(
int
z
=
0
; z < GrowBuffer.size(); z
+
+
)
{
CurrX
=
GrowBuffer.at(z).x;
CurrY
=
GrowBuffer.at(z).y;
PointLabel.at<uchar>(CurrY, CurrX)
+
=
CheckResult;
/
/
标记不合格的像素点,像素值为
2
}
/
/
*
*
*
*
*
*
*
*
结束该点处的检查
*
*
*
*
*
*
*
*
*
*
}
}
}
CheckMode
=
255
*
(
1
-
CheckMode);
/
/
开始反转面积过小的区域
for
(
int
i
=
0
; i < Src.rows;
+
+
i)
{
for
(
int
j
=
0
; j < Src.cols;
+
+
j)
{
if
(PointLabel.at<uchar>(i, j)
=
=
2
)
{
Dst.at<uchar>(i, j)
=
CheckMode;
}
else
if
(PointLabel.at<uchar>(i, j)
=
=
3
)
{
Dst.at<uchar>(i, j)
=
Src.at<uchar>(i, j);
}
}
}
/
/
cout << RemoveCount <<
" objects removed."
<< endl;
}
/
/
=
=
=
=
=
=
=
函数实现
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
/
/
=
=
=
=
=
=
=
调用函数
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
Mat img;
img
=
imread(
"D:1_1.jpg"
,
0
);
/
/
读取图片
threshold(img, img,
128
,
255
, CV_THRESH_BINARY_INV);
imshow(
"去除前"
, img);
Mat img1;
RemoveSmallRegion(img, img,
200
,
0
,
1
);
imshow(
"去除后"
, img);
waitKey(
0
);
/
/
=
=
=
=
=
=
=
调用函数
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
以上这篇使用OpenCV去除面积较小的连通域就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/sxlsxl119/article/details/80493655