图像分割与距离变换和流域算法

举报
鱼酱 发表于 2022/01/07 00:56:27 2022/01/07
【摘要】 1.文章内容   使用OpenCV函数cv ::filter2D为了执行一些拉普拉斯过滤,来进行图像锐化  使用OpenCV函数cv ::distanceTransform来获得二进制图像的导出表示,其中每个像素的值被替换为最近的背景像素的距离  使用OpenCV函数cv ::watershed来隔离图像...

1.文章内容

  •   使用OpenCV函数cv ::filter2D为了执行一些拉普拉斯过滤,来进行图像锐化
  •   使用OpenCV函数cv ::distanceTransform来获得二进制图像的导出表示,
  • 其中每个像素的值被替换为最近的背景像素的距离
  •   使用OpenCV函数cv ::watershed来隔离图像中的对象与背景


2.教程

This tutorial code's is shown lines below. You can also download it from here.


  
  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. using namespace std;
  4. using namespace cv;
  5. int main(int, char** argv)
  6. {
  7. // Load the image 加载图片
  8. Mat src = imread(argv[1]);
  9. // Check if everything was fine 检查数据是否完好
  10. if (!src.data)
  11. return -1;
  12. // Show source image 展示原图片
  13. imshow("Source Image", src);
  14. // Change the background from white to black, since that will help later to extract
  15. //改变背景从白色到黑色,因为这将有助于以后提取
  16. // better results during the use of Distance Transform
  17. //使用距离变换更好的效果
  18. for( int x = 0; x < src.rows; x++ ) {
  19. for( int y = 0; y < src.cols; y++ ) {
  20. if ( src.at<Vec3b>(x, y) == Vec3b(255,255,255) ) {
  21. src.at<Vec3b>(x, y)[0] = 0;
  22. src.at<Vec3b>(x, y)[1] = 0;
  23. src.at<Vec3b>(x, y)[2] = 0;
  24. }
  25. }
  26. }
  27. // Show output image 展示输出图片
  28. imshow("Black Background Image", src);
  29. // Create a kernel that we will use for accuting/sharpening our image
  30. //创建一个我们将用于核算/锐化我们的图像的内核
  31. Mat kernel = (Mat_<float>(3,3) <<
  32. 1, 1, 1,
  33. 1, -8, 1,
  34. 1, 1, 1); // an approximation of second derivative, a quite strong kernel
  35. //二阶导数近似值,一个相当强的内核
  36. // do the laplacian filtering as it is
  37. // well, we need to convert everything in something more deeper then CV_8U
  38. // because the kernel has some negative values,
  39. // and we can expect in general to have a Laplacian image with negative values
  40. // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
  41. // so the possible negative number will be truncated
  42. //执行拉普拉斯滤镜
  43. //好了,我们需要将所有东西都转换成更深层次的东西,然后CV_8U
  44. //因为内核有一些负值,
  45. //我们可以期待一般来说具有负值的拉普拉斯图像
  46. //但是一个8bits unsigned int(我们正在使用的)可以包含从0到255的值
  47. //所以可能的负数将被截断
  48. Mat imgLaplacian;
  49. Mat sharp = src; // copy source image to another temporary one
  50. filter2D(sharp, imgLaplacian, CV_32F, kernel);
  51. src.convertTo(sharp, CV_32F);
  52. Mat imgResult = sharp - imgLaplacian;
  53. // convert back to 8bits gray scale
  54. //转换为8位灰度
  55. imgResult.convertTo(imgResult, CV_8UC3);
  56. imgLaplacian.convertTo(imgLaplacian, CV_8UC3);
  57. // imshow( "Laplace Filtered Image", imgLaplacian );
  58. imshow( "New Sharped Image", imgResult );
  59. src = imgResult; // copy back
  60. // Create binary image from source image
  61. //从源图像创建二进制图像
  62. Mat bw;
  63. cvtColor(src, bw, CV_BGR2GRAY);
  64. threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
  65. imshow("Binary Image", bw);
  66. // Perform the distance transform algorithm
  67. //执行距离变换算法
  68. Mat dist;
  69. distanceTransform(bw, dist, CV_DIST_L2, 3);
  70. // Normalize the distance image for range = {0.0, 1.0}
  71. // so we can visualize and threshold it
  72. //范围= {0.0,1.0}的距离图像归一化
  73. //所以我们可以可视化和限制它 normalize(dist, dist, 0, 1., NORM_MINMAX);
  74. imshow("Distance Transform Image", dist);
  75. // Threshold to obtain the peaks
  76. // This will be the markers for the foreground objects
  77. //获取峰值的阈值
  78. //这将是前景对象的标记
  79. threshold(dist, dist, .4, 1., CV_THRESH_BINARY);
  80. // Dilate a bit the dist image
  81. //稀释一点dist图像
  82. Mat kernel1 = Mat::ones(3, 3, CV_8UC1);
  83. dilate(dist, dist, kernel1);
  84. imshow("Peaks", dist);
  85. // Create the CV_8U version of the distance image
  86. // It is needed for findContours()
  87. //创建CV_8U版本的距离图像
  88. // findContours()需要
  89. Mat dist_8u;
  90. dist.convertTo(dist_8u, CV_8U);
  91. // Find total markers
  92. //查找总标记
  93. vector<vector<Point> > contours;
  94. findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
  95. // Create the marker image for the watershed algorithm
  96. //为分水岭算法创建标记图像
  97. Mat markers = Mat::zeros(dist.size(), CV_32SC1);
  98. // Draw the foreground markers
  99. //绘制前景标记
  100. for (size_t i = 0; i < contours.size(); i++)
  101. drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
  102. // Draw the background marker
  103. //绘制背景标记
  104. circle(markers, Point(5,5), 3, CV_RGB(255,255,255), -1);
  105. imshow("Markers", markers*10000);
  106. // Perform the watershed algorithm
  107. //执行分水岭算法
  108. watershed(src, markers);
  109. Mat mark = Mat::zeros(markers.size(), CV_8UC1);
  110. markers.convertTo(mark, CV_8UC1);
  111. bitwise_not(mark, mark);
  112. // imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
  113. // image looks like at that point
  114. //取消注释,如果你想看看如何标记
  115. //图像看起来就像这样
  116. // Generate random colors
  117. //生成随机颜色
  118. vector<Vec3b> colors;
  119. for (size_t i = 0; i < contours.size(); i++)
  120. {
  121. int b = theRNG().uniform(0, 255);
  122. int g = theRNG().uniform(0, 255);
  123. int r = theRNG().uniform(0, 255);
  124. colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
  125. }
  126. // Create the result image
  127. //创建结果图像
  128. Mat dst = Mat::zeros(markers.size(), CV_8UC3);
  129. // Fill labeled objects with random colors
  130. //用随机颜色填充标签对象
  131. for (int i = 0; i < markers.rows; i++)
  132. {
  133. for (int j = 0; j < markers.cols; j++)
  134. {
  135. int index = markers.at<int>(i,j);
  136. if (index > 0 && index <= static_cast<int>(contours.size()))
  137. dst.at<Vec3b>(i,j) = colors[index-1];
  138. else
  139. dst.at<Vec3b>(i,j) = Vec3b(0,0,0);
  140. }
  141. }
  142. // Visualize the final image
  143. //可视化最终图像
  144. imshow("Final Result", dst);
  145. waitKey(0);
  146. return 0;
  147. }


3.解释/结果

  

        1.加载源图像并检查是否加载没有任何问题,然后显示


  
  1. // Load the image 加载图片
  2. Mat src = imread(argv[1]);
  3. // Check if everything was fine
  4. if (!src.data)
  5. return -1;
  6. // Show source image 展示图片
  7. imshow("Source Image", src);







文章来源: yujiang.blog.csdn.net,作者:鱼酱2333,版权归原作者所有,如需转载,请联系作者。

原文链接:yujiang.blog.csdn.net/article/details/69941997

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。