OTSU阈值化

来源:互联网 发布:3d打印机切片软件 编辑:程序博客网 时间:2024/06/05 05:30
在阈值处理中,常用的算法就是OTSU,OTSU是在1979年提出的一种寻找图像阈值的最大类间方差算法。
步骤如下:
1.统计灰度及中每个像素在整幅图中的个数
2.计算每个像素在整幅图像中的概率分布
3.对灰度级进行遍历搜索,计算当前灰度下前景背景类间概率
4.通过目标函数计算出类内与类间方差下对应的阈值
代码如下:
  1. #include "opencv2/highgui/highgui.hpp"
  2. #include "opencv2/opencv.hpp"
  3. #include "opencv2/core/core.hpp"
  4. #include <stdio.h>
  5. #include <string>
  6. using namespace std;
  7. using namespace cv;
  8. //OTSU函数实现
  9. int OTSU(cv::Mat srcImage)
  10. {
  11. int nCols = srcImage.cols;
  12. int nRows = srcImage.rows;
  13. int threshold = 0;
  14. //统计初始化参数
  15. int nSumPix[256];
  16. float nProDis[256];
  17. for (int i = 0; i < 256; i++)
  18. {
  19. nSumPix[i] = 0;
  20. nProDis[i] = 0;
  21. }
  22. //统计灰度级中每个像素在整附图中的个数
  23. for (int i = 0; i < nRows; i++)
  24. {
  25. for (int j = 0; j < nCols; j++)
  26. {
  27. nSumPix[(int)srcImage.at<uchar>(i,j)]++;
  28. }
  29. }
  30. //计算每个灰度级占图像中的概率分布
  31. for (int i = 0; i < 256; i++)
  32. {
  33. nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
  34. }
  35. //遍历灰度级[0, 255],计算出最大类间方差下的阈值
  36. float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
  37. float delta_max = 0;
  38. for (int i = 0; i < 256; i++)
  39. {
  40. //初始化相关参数
  41. w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
  42. for (int j = 0; j < 256; j++)
  43. {
  44. //背景部分
  45. if (j <= i)
  46. {
  47. //当前i为分割阈值,第一类总的概率
  48. w0 += nProDis[j];
  49. u0_temp += j * nProDis[j];
  50. }
  51. //前景部分
  52. else
  53. {
  54. //当前i为分割阈值,第一类总的概率
  55. w1 += nProDis[j];
  56. u1_temp += j * nProDis[j];
  57. }
  58. }
  59. //计算各类的平均灰度
  60. u0 = u0_temp / w0;
  61. u1 = u1_temp / w1;
  62. delta_temp = (float)(w0 * w1 * pow((u0 - u1), 2));
  63. //依次找到最大类间方差下的阈值
  64. if (delta_temp > delta_max)
  65. {
  66. delta_max = delta_temp;
  67. threshold = i;
  68. }
  69. }
  70. return threshold;
  71. }
  72. int main()
  73. {
  74. cv::Mat srcImage = cv::imread("C:\\Users\\LP\\Desktop\\C++\\ConsoleApplication4\\ConsoleApplication4\\RGBFlower4.jpg");
  75. if (srcImage.empty())
  76. {
  77. return -1;
  78. }
  79. cv::imshow("原图像", srcImage);
  80. //灰度转换
  81. cv::Mat srcGray;
  82. cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
  83. cv::imshow("srcGray", srcGray);
  84. //调用OTSU二值化算法得到阈值
  85. int ostuThreshold = OTSU(srcGray);
  86. std::cout << ostuThreshold << std::endl;
  87. //定义输出结果图像
  88. cv::Mat otsuResultImage = cv::Mat::zeros( srcGray.rows, srcGray.cols, CV_8UC1);
  89. //利用得到的阈值进行二值化操作
  90. for (int i = 0; i < srcGray.rows; i++)
  91. {
  92. for (int j = 0; j < srcGray.cols; j++)
  93. {
  94. //高像素阈值判断
  95. if (srcGray.at<uchar>(i,j) > ostuThreshold)
  96. {
  97. otsuResultImage.at<uchar>(i,j) = 255;
  98. }
  99. else
  100. {
  101. otsuResultImage.at<uchar>(i,j) = 0;
  102. }
  103. }
  104. }
  105. cv::imshow("otsuResultImage", otsuResultImage);
  106. cv::waitKey(0);
  107. return 0;
  108. }
原创粉丝点击