opencv分水岭算法分硬币
时间: 2024-12-30 14:29:08 浏览: 7
### 使用 OpenCV 的分水岭算法进行硬币图像分割
为了实现硬币图像的精确分割,可以采用基于标记的分水岭算法。该方法通过预先定义前景、背景以及未知区域来指导分水岭变换过程,从而减少过分割现象的发生。
#### 准备工作
首先加载待处理的图片并检查其有效性:
```cpp
Mat src = imread("C:/opencv/data/coins.jpg");
if (src.empty()) {
printf("Could not load image...\n");
return -1;
}
```
这段代码用于读取指定路径下的图像文件,并验证是否成功加载[^1]。
#### 图像预处理
通常情况下,在执行分水岭之前需要对原始图像做一些必要的预处理操作,比如灰度化转换、高斯模糊降噪和平滑滤波等:
```cpp
// 转换成灰度图
cvtColor(src, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, blurred, Size(7, 7), 0);
// 应用二值化阈值处理
threshold(blurred, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
```
这些步骤有助于提高后续边缘检测的效果,使得最终得到更清晰的目标轮廓[^2]。
#### 创建 Marker Map
创建一个 marker map 来标注已知的信息(即确定属于物体内部或外部的部分),并将剩余部分设为未定状态 (-1 表示未知):
```cpp
// 执行形态学开运算去除小斑点
morphologyEx(binary, sure_bg, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(3, 3)));
// 计算距离变换获取可能的核心区域
distanceTransform(sure_bg, dist_transform, DIST_L2, 3);
normalize(dist_transform, dist_transform, 0, 1.0, NORM_MINMAX);
// 阈值化获得可靠的前景估计
threshold(dist_transform, sure_fg, 0.7 * dist_transform.maxVal(), 255, 0);
// 将前景和背景相减找出未知区域
subtract(sure_bg, sure_fg, unknown);
// 定义连通域标签
connectedComponents(sure_fg, markers);
// 给未知区赋值为零准备watershed填充
markers = markers + 1;
markers(unknown == 255) = 0;
```
此段程序构建了一个初步的marker映射表,其中包含了明确分类好的像素位置及其对应的类别编号;同时保留了一片空白供之后由算法自动填补[^3]。
#### 应用分水岭变换
调用 `cv::watershed()` 函数完成实际的分割任务:
```cpp
watershed(src, markers);
// 结果可视化
Mat watershed_output;
convertScaleAbs(markers, watershed_output);
watershed_output.convertTo(watershed_output, CV_8UC3);
imshow("Watershed Segmentation", watershed_output);
waitKey();
```
经过上述流程后,`markers` 中原本设置为 `-1` 的边界线现在已经被正确地标记出来,形成了完整的分割效果。
阅读全文