1、连通域
//连通域
int test1()
{
//对图像进行距离变换
Mat img = imread("F:/testMap/rice.png");
if (img.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat rice, riceBW;
//将图像转成二值图像,用于统计连通域
cvtColor(img, rice, COLOR_BGR2GRAY);//先转为灰度图
threshold(rice, riceBW, 50, 255, THRESH_BINARY);//再二值化
//生成随机颜色,用于区分不同连通域
RNG rng(10086);
Mat out;
int number = connectedComponents(riceBW, out, 8, CV_16U);//统计图像中连通域的个数
vector<Vec3b> colors;
for (int i = 0; i < number; i++)
{
//使用均匀分布的随机数确定颜色
Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
colors.push_back(vec3);
//以不同颜色标记出不同的连通域
Mat result = Mat::zeros(rice.size(), img.type());
int w = result.cols;
int h = result.rows;
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
int label = out.at<uint16_t>(row, col);
if (label == 0)//背景的黑色不改变
{
continue;
}
result.at<Vec3b>(row, col) = colors[label];
}
}
//显示结果
imshow("原图", img);
imshow("标记后的图像", result);
cout << "接下来统计连通域信息" << endl;
waitKey(0);
Mat stats, centroids;
number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);
vector<Vec3b> colors_new;
for (int i = 0; i < number; i++)
{
//使用均匀分布的随机数确定颜色
Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
colors_new.push_back(vec3);
}
//以不同颜色标记出不同的连通域
for (int i = 1; i < number; i++)
{
//中心位置
int center_x = centroids.at<double>(i, 0);
int center_y = centroids.at<double>(i, 1);
//矩形边框
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int w = stats.at<int>(i, CC_STAT_WIDTH);
int h = stats.at<int>(i, CC_STAT_HEIGHT);
int area = stats.at<int>(i, CC_STAT_AREA);
//中心位置绘制
circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);
//外接矩形
Rect rect(x, y, w, h);
rectangle(img, rect, colors_new[i], 1, 8, 0);
putText(img, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
cout << "number: " << i << " , area: " << area << endl;
}
//显示结果
imshow("标记后的图像", img);
waitKey(0);
return 0;
}
}
1.1 连通域分割原理
1.2 连通域分割函数
2、相距变换
2.1 像素间距离
2.2 距离变换函数
//图像距离变换
int test2()
{
//构建建议矩阵,用于求取像素之间的距离
Mat a = (Mat_<uchar>(5, 5) << 1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 0, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1);
Mat dist_L1, dist_L2, dist_C, dist_L12;
//计算街区距离
distanceTransform(a, dist_L1, 1, 3, CV_8U);
cout << "街区距离:" << endl << dist_L1 << endl;
//计算欧式距离
distanceTransform(a, dist_L2, 2, 5, CV_8U);
cout << "欧式距离:" << endl << dist_L2 << endl;
//计算棋盘距离
distanceTransform(a, dist_C, 3, 5, CV_8U);
cout << "棋盘距离:" << endl << dist_C << endl;
cout << "对图像进行距离变换" << endl; waitKey(0);
Mat rice = imread("F:/testMap/rice.png", IMREAD_GRAYSCALE);
if (rice.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat riceBW, riceBW_INV;
//将图像转成二值图像,同时把黑白区域颜色互换
threshold(rice, riceBW, 50, 255, THRESH_BINARY);
threshold(rice, riceBW_INV, 50, 255, THRESH_BINARY_INV);
//距离变换
Mat dist, dist_INV;
distanceTransform(riceBW, dist, 1, 3, CV_32F);
//为了显示清晰,将数据类型变成 CV_32F
distanceTransform(riceBW_INV, dist_INV, 1, 3, CV_8U);
//显示变换结果
imshow("riceBW", riceBW);
imshow("dist", dist);
imshow("riceBW_INV", riceBW_INV);
imshow("dist_INV", dist_INV);
waitKey(0);
return 0;
}