本文共 2238 字,大约阅读时间需要 7 分钟。
本文将详细介绍如何利用OpenCV库中的分水岭算法对图像进行背景与目标物体的分割。通过对图像进行预处理、均值偏移变换、距离变换以及分水岭变换等步骤,实现精准的图像分割。
首先,我们需要读取输入图像,确保图像加载成功。代码中使用了imread函数读取指定路径的图像文件,并检查图像是否加载成功。
Mat src = imread("E:\\vs2015\\opencvstudy\\2kmeans.jpg", 1);if (src.empty()) { cout << "could not load the image!" << endl; return -1;}imshow("input", src); 接下来,我们对图像进行均值偏移变换,参数设置为21和51。均值偏移变换能够有效地减少图像的噪声,提高后续处理的效果。
Mat gray, binary, shifted;pyrMeanShiftFiltering(src, shifted, 21, 51);imshow("shifted:", shifted); 将均值偏移变换后的图像转换为灰度格式,并使用阈值操作将图像转换为二值图像。
cvtColor(shifted, gray, COLOR_BGR2GRAY);threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
通过距离变换,我们可以计算图像中每个像素与其最近目标物体的距离,这一步为后续的分水岭变换奠定基础。
Mat dist;distanceTransform(binary, dist, DistanceTypes::DIST_L2, 3, CV_32F);normalize(dist, dist, 0, 1, NORM_MINMAX);
在距离图像基础上,我们使用分水岭变换算法对图像进行背景与目标物体的分割。通过创建标记图像并进行形态学操作,实现最终的图像分割。
Mat markers = Mat::zeros(src.size(), CV_32SC1);for (size_t i = 0; i < contours.size(); i++) { drawContours(markers, contours, static_cast (i), Scalar::all(static_cast (i) + 1), -1);}circle(markers, Point(5, 5), 3, Scalar(255), -1);imshow("markers", markers * 10000);watershed(src, markers);Mat mark = Mat::zeros(markers.size(), CV_8UC1);bitwise_not(mark, mark, Mat());imshow("watershedResult", mark); 最后,我们对每个轮廓区域进行颜色填充,并将结果显示出来。
vectorcolors;for (size_t i = 0; i < contours.size(); i++) { int r = theRNG().uniform(0, 255); int g = theRNG().uniform(0, 255); int b = theRNG().uniform(0, 255); colors.push_back(Vec3b((uchar)r, (uchar)g, (uchar)b));}Mat dst = Mat::zeros(markers.size(), CV_8UC3);for (int row = 0; row < markers.rows; row++) { for (int col = 0; col < markers.cols; col++) { int index = markers.at (row, col); if (index > 0 && index <= static_cast (contours.size())) { dst.at (row, col) = colors[index - 1]; } else { dst.at (row, col) = Vec3b(0, 0, 0); } }}imshow("dst", dst);cout << "轮廓个数:" << contours.size() << endl;waitKey(0);return 0;
运行上述代码,您将看到分水岭算法处理后的图像结果。分水岭算法通过计算图像的距离场,并结合形态学操作和标记填充,实现了对复杂背景图像的精准分割。这一方法在目标检测、图像分割等领域具有广泛的应用价值。
转载地址:http://ygsfk.baihongyu.com/