imageSegmentation.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed and Distance Transformation
  3. * @author OpenCV Team
  4. */
  5. #include <opencv2/core.hpp>
  6. #include <opencv2/imgproc.hpp>
  7. #include <opencv2/highgui.hpp>
  8. #include <iostream>
  9. using namespace std;
  10. using namespace cv;
  11. int main(int argc, char *argv[])
  12. {
  13. //! [load_image]
  14. // Load the image
  15. CommandLineParser parser( argc, argv, "{@input | cards.png | input image}" );
  16. Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
  17. if( src.empty() )
  18. {
  19. cout << "Could not open or find the image!\n" << endl;
  20. cout << "Usage: " << argv[0] << " <Input image>" << endl;
  21. return -1;
  22. }
  23. // Show the source image
  24. imshow("Source Image", src);
  25. //! [load_image]
  26. //! [black_bg]
  27. // Change the background from white to black, since that will help later to extract
  28. // better results during the use of Distance Transform
  29. Mat mask;
  30. inRange(src, Scalar(255, 255, 255), Scalar(255, 255, 255), mask);
  31. src.setTo(Scalar(0, 0, 0), mask);
  32. // Show output image
  33. imshow("Black Background Image", src);
  34. //! [black_bg]
  35. //! [sharp]
  36. // Create a kernel that we will use to sharpen our image
  37. Mat kernel = (Mat_<float>(3,3) <<
  38. 1, 1, 1,
  39. 1, -8, 1,
  40. 1, 1, 1); // an approximation of second derivative, a quite strong kernel
  41. // do the laplacian filtering as it is
  42. // well, we need to convert everything in something more deeper then CV_8U
  43. // because the kernel has some negative values,
  44. // and we can expect in general to have a Laplacian image with negative values
  45. // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
  46. // so the possible negative number will be truncated
  47. Mat imgLaplacian;
  48. filter2D(src, imgLaplacian, CV_32F, kernel);
  49. Mat sharp;
  50. src.convertTo(sharp, CV_32F);
  51. Mat imgResult = sharp - imgLaplacian;
  52. // convert back to 8bits gray scale
  53. imgResult.convertTo(imgResult, CV_8UC3);
  54. imgLaplacian.convertTo(imgLaplacian, CV_8UC3);
  55. // imshow( "Laplace Filtered Image", imgLaplacian );
  56. imshow( "New Sharped Image", imgResult );
  57. //! [sharp]
  58. //! [bin]
  59. // Create binary image from source image
  60. Mat bw;
  61. cvtColor(imgResult, bw, COLOR_BGR2GRAY);
  62. threshold(bw, bw, 40, 255, THRESH_BINARY | THRESH_OTSU);
  63. imshow("Binary Image", bw);
  64. //! [bin]
  65. //! [dist]
  66. // Perform the distance transform algorithm
  67. Mat dist;
  68. distanceTransform(bw, dist, DIST_L2, 3);
  69. // Normalize the distance image for range = {0.0, 1.0}
  70. // so we can visualize and threshold it
  71. normalize(dist, dist, 0, 1.0, NORM_MINMAX);
  72. imshow("Distance Transform Image", dist);
  73. //! [dist]
  74. //! [peaks]
  75. // Threshold to obtain the peaks
  76. // This will be the markers for the foreground objects
  77. threshold(dist, dist, 0.4, 1.0, THRESH_BINARY);
  78. // Dilate a bit the dist image
  79. Mat kernel1 = Mat::ones(3, 3, CV_8U);
  80. dilate(dist, dist, kernel1);
  81. imshow("Peaks", dist);
  82. //! [peaks]
  83. //! [seeds]
  84. // Create the CV_8U version of the distance image
  85. // It is needed for findContours()
  86. Mat dist_8u;
  87. dist.convertTo(dist_8u, CV_8U);
  88. // Find total markers
  89. vector<vector<Point> > contours;
  90. findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
  91. // Create the marker image for the watershed algorithm
  92. Mat markers = Mat::zeros(dist.size(), CV_32S);
  93. // Draw the foreground markers
  94. for (size_t i = 0; i < contours.size(); i++)
  95. {
  96. drawContours(markers, contours, static_cast<int>(i), Scalar(static_cast<int>(i)+1), -1);
  97. }
  98. // Draw the background marker
  99. circle(markers, Point(5,5), 3, Scalar(255), -1);
  100. Mat markers8u;
  101. markers.convertTo(markers8u, CV_8U, 10);
  102. imshow("Markers", markers8u);
  103. //! [seeds]
  104. //! [watershed]
  105. // Perform the watershed algorithm
  106. watershed(imgResult, markers);
  107. Mat mark;
  108. markers.convertTo(mark, CV_8U);
  109. bitwise_not(mark, mark);
  110. // imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
  111. // image looks like at that point
  112. // Generate random colors
  113. vector<Vec3b> colors;
  114. for (size_t i = 0; i < contours.size(); i++)
  115. {
  116. int b = theRNG().uniform(0, 256);
  117. int g = theRNG().uniform(0, 256);
  118. int r = theRNG().uniform(0, 256);
  119. colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
  120. }
  121. // Create the result image
  122. Mat dst = Mat::zeros(markers.size(), CV_8UC3);
  123. // Fill labeled objects with random colors
  124. for (int i = 0; i < markers.rows; i++)
  125. {
  126. for (int j = 0; j < markers.cols; j++)
  127. {
  128. int index = markers.at<int>(i,j);
  129. if (index > 0 && index <= static_cast<int>(contours.size()))
  130. {
  131. dst.at<Vec3b>(i,j) = colors[index-1];
  132. }
  133. }
  134. }
  135. // Visualize the final image
  136. imshow("Final Result", dst);
  137. //! [watershed]
  138. waitKey();
  139. return 0;
  140. }