OpenCV(四十一):图像分割-分水岭法

落日映苍穹つ 2024-03-03 08:31 188阅读 0赞

1.分水岭方法介绍

OpenCV 提供了分水岭算法(Watershed Algorithm)的实现, 使用分水岭算法对图像进行分割,将图像的不同区域分割成互不干扰的区域。分水岭算法模拟了水在图像中的扩散和聚集过程,将标记的边界被看作是阻挡水扩散的高山,通过模拟水的扩散和聚集,最终确定图像的分割边界。

如图所示:水从山低蔓延,而高山阻止水扩散。

8553a0ef29e641dc89d4071897e82b59.png

2.分水岭法分割图像函数watershed()

void cv::watershed ( InputArray image,

InputOutputArray markers

  • image:输入图像,数据类型为CV_8U的三通道图像
  • markers:输入/输出CV_32S的单通道图像的标记结果,与原图像具有相同的尺寸

示例代码:

基于标记图像中画的线来对原图像进行分割。

  1. void watershed_f(Mat mat,Mat mat2){//mat原图像 mat2含有标记的图像
  2. // 把四通道原图像转换成三通道
  3. Mat image;
  4. cv::cvtColor(mat, image, cv::COLOR_BGRA2BGR);
  5. Mat imgGray,imgMask,img_;
  6. Mat maskWaterShed;//watershed()函数的参数
  7. //对标记的图像进行灰度化
  8. Mat image2;
  9. cvtColor(mat2,imgGray,COLOR_BGR2GRAY);
  10. //对标记的图像二值化并开运算,可得到标记画的线
  11. threshold(imgGray,imgMask,250,255,THRESH_BINARY);
  12. Mat k= getStructuringElement(0,Size(3,3));
  13. morphologyEx(imgMask,imgMask,MORPH_OPEN,k);
  14. //显示二值化并开运算的结果
  15. imwrite("/sdcard/DCIM/imgMask2.png",imgMask);
  16. //对二值化后的标记图像进行轮廓检测,可得到画的线的轮廓
  17. vector<vector<Point>> contours;
  18. vector<Vec4i> hierarchy;
  19. findContours(imgMask,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
  20. //在maskWaterShed上绘制出上面得到的轮廓
  21. maskWaterShed=Mat::zeros(imgMask.size(),CV_32S);
  22. for(int index=0;index<contours.size();index++){
  23. drawContours(maskWaterShed,contours,index,Scalar::all(index+1),2,8);
  24. }
  25. //分水岭算法 需要对原图像进行处理
  26. watershed(image,maskWaterShed);
  27. //显示分水岭算法分割的每个区域
  28. imwrite("/sdcard/DCIM/maskWaterShed2.png",maskWaterShed);
  29. //随机生成几种颜色
  30. vector<Vec3b> colors;
  31. for(int i=0;i<contours.size();i++){
  32. int b=theRNG().uniform(0,255);
  33. int g=theRNG().uniform(0,255);
  34. int r=theRNG().uniform(0,255);
  35. colors.push_back(Vec3b((uchar)b,(uchar)g,(uchar)r));
  36. }
  37. //给分水岭算法分割的每个区域添加颜色
  38. Mat resultImg=Mat(image2.size(),CV_8UC3);
  39. for(int i=0;i<imgMask.rows;i++){
  40. for(int j=0;j<imgMask.cols;j++){
  41. //绘制每个区域的颜色
  42. int index=maskWaterShed.at<int>(i,j);
  43. if(index==-1)//区域间的值被置为-1(边界)
  44. {
  45. resultImg.at<Vec3b>(i,j)=Vec3b(255,255,255);
  46. }
  47. else if(index<=0||index>contours.size())//没有标记清楚的区域被置为0
  48. {
  49. resultImg.at<Vec3b>(i,j)=Vec3b(0,0,0);
  50. }else{
  51. resultImg.at<Vec3b>(i,j)=colors[index-1];
  52. }
  53. }
  54. }
  55. //显示给分水岭算法分割的每个区域添加颜色的结果
  56. imwrite("/sdcard/DCIM/resultImg2.png",resultImg);
  57. //分割的区域与原图像结合
  58. resultImg=resultImg*0.8+image*0.2;
  59. imwrite("/sdcard/DCIM/resultImg3.png",resultImg);
  60. }

85bbc248ac744307849c7f1fd46ffad3.png

0c2529565aa3430491727967c786ffbd.png

db5a535a8b2b4d2e86b832cc79e78fb4.png

发表评论

表情:
评论列表 (有 0 条评论,188人围观)

还没有评论,来说两句吧...

相关阅读