1.分水岭方法介绍
OpenCV 提供了分水岭算法(Watershed Algorithm)的实现, 使用分水岭算法对图像进行分割,将图像的不同区域分割成互不干扰的区域。分水岭算法模拟了水在图像中的扩散和聚集过程,将标记的边界被看作是阻挡水扩散的高山,通过模拟水的扩散和聚集,最终确定图像的分割边界。
如图所示:水从山低蔓延,而高山阻止水扩散。
2.分水岭法分割图像函数watershed()
void cv::watershed ( InputArray image,
InputOutputArray markers
)
- image:输入图像,数据类型为CV_8U的三通道图像
- markers:输入/输出CV_32S的单通道图像的标记结果,与原图像具有相同的尺寸
示例代码:
基于标记图像中画的线来对原图像进行分割。
void watershed_f(Mat mat,Mat mat2){//mat原图像 mat2含有标记的图像 // 把四通道原图像转换成三通道 Mat image; cv::cvtColor(mat, image, cv::COLOR_BGRA2BGR); Mat imgGray,imgMask,img_; Mat maskWaterShed;//watershed()函数的参数 //对标记的图像进行灰度化 Mat image2; cvtColor(mat2,imgGray,COLOR_BGR2GRAY); //对标记的图像二值化并开运算,可得到标记画的线 threshold(imgGray,imgMask,250,255,THRESH_BINARY); Mat k= getStructuringElement(0,Size(3,3)); morphologyEx(imgMask,imgMask,MORPH_OPEN,k); //显示二值化并开运算的结果 imwrite("/sdcard/DCIM/imgMask2.png",imgMask); //对二值化后的标记图像进行轮廓检测,可得到画的线的轮廓 vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(imgMask,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point()); //在maskWaterShed上绘制出上面得到的轮廓 maskWaterShed=Mat::zeros(imgMask.size(),CV_32S); for(int index=0;index<contours.size();index++){ drawContours(maskWaterShed,contours,index,Scalar::all(index+1),2,8); } //分水岭算法 需要对原图像进行处理 watershed(image,maskWaterShed); //显示分水岭算法分割的每个区域 imwrite("/sdcard/DCIM/maskWaterShed2.png",maskWaterShed); //随机生成几种颜色 vector<Vec3b> colors; for(int i=0;i<contours.size();i++){ int b=theRNG().uniform(0,255); int g=theRNG().uniform(0,255); int r=theRNG().uniform(0,255); colors.push_back(Vec3b((uchar)b,(uchar)g,(uchar)r)); } //给分水岭算法分割的每个区域添加颜色 Mat resultImg=Mat(image2.size(),CV_8UC3); for(int i=0;i<imgMask.rows;i++){ for(int j=0;j<imgMask.cols;j++){ //绘制每个区域的颜色 int index=maskWaterShed.at<int>(i,j); if(index==-1)//区域间的值被置为-1(边界) { resultImg.at<Vec3b>(i,j)=Vec3b(255,255,255); } else if(index<=0||index>contours.size())//没有标记清楚的区域被置为0 { resultImg.at<Vec3b>(i,j)=Vec3b(0,0,0); }else{ resultImg.at<Vec3b>(i,j)=colors[index-1]; } } } //显示给分水岭算法分割的每个区域添加颜色的结果 imwrite("/sdcard/DCIM/resultImg2.png",resultImg); //分割的区域与原图像结合 resultImg=resultImg*0.8+image*0.2; imwrite("/sdcard/DCIM/resultImg3.png",resultImg); }