Advertisement
dan-masek

For https://stackoverflow.com/q/78171957/3962537

Mar 16th, 2024 (edited)
671
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.06 KB | None | 0 0
  1. #include <chrono>
  2.  
  3. #include <opencv2/opencv.hpp>
  4.  
  5. // ===================================================================
  6.  
  7. namespace original {
  8.  
  9. double CalculateCriteria(const cv::Mat& im, int th)
  10. {
  11.     cv::Mat thresholdedIm = cv::Mat::zeros(im.size(), CV_64F);
  12.     thresholdedIm.setTo(1, im >= th);
  13.  
  14.     double nbPixels = static_cast<double>(im.total());
  15.     double nbPixels1 = cv::countNonZero(thresholdedIm);
  16.     double weight1 = nbPixels1 / nbPixels;
  17.     double weight0 = 1 - weight1;
  18.  
  19.     if (weight1 == 0 || weight0 == 0) {
  20.         return std::numeric_limits<double>::infinity();
  21.     }
  22.  
  23.     cv::Mat valPixels1, valPixels0;
  24.     im.copyTo(valPixels1, thresholdedIm == 1);
  25.     im.copyTo(valPixels0, thresholdedIm == 0);
  26.  
  27.     cv::Scalar mean1, stdDev1, mean0, stdDev0;
  28.     cv::meanStdDev(valPixels1, mean1, stdDev1);
  29.     cv::meanStdDev(valPixels0, mean0, stdDev0);
  30.  
  31.     double var1 = stdDev1[0] * stdDev1[0];
  32.     double var0 = stdDev0[0] * stdDev0[0];
  33.  
  34.     return weight0 * var0 + weight1 * var1;
  35. }
  36.  
  37. cv::Mat SelectThreshold(const cv::Mat& img)
  38. {
  39.     int maxVal = 255;
  40.     std::vector<double> criterias;
  41.     for (int th = 0; th <= maxVal; ++th) {
  42.         criterias.push_back(original::CalculateCriteria(img, th));
  43.     }
  44.  
  45.     auto minElement = std::min_element(criterias.begin(), criterias.end());
  46.     int bestThreshold = static_cast<int>(std::distance(criterias.begin(), minElement));
  47.  
  48.     cv::Mat binary;
  49.     cv::threshold(img, binary, bestThreshold, 255, cv::THRESH_BINARY);
  50.  
  51.     return binary;
  52. }
  53.  
  54. } // namespace original
  55.  
  56. // ===================================================================
  57.  
  58. namespace dans1 {
  59.  
  60.     double CalculateCriteria(const cv::Mat& im, int th)
  61.     {
  62.         cv::Mat thresholdedIm = (im >= th);
  63.  
  64.         double nbPixels = static_cast<double>(im.total());
  65.         double nbPixels1 = cv::countNonZero(thresholdedIm);
  66.         double weight1 = nbPixels1 / nbPixels;
  67.         double weight0 = 1 - weight1;
  68.  
  69.         if (weight1 == 0 || weight0 == 0) {
  70.             return std::numeric_limits<double>::infinity();
  71.         }
  72.  
  73.         cv::Mat valPixels1, valPixels0;
  74.         im.copyTo(valPixels1, thresholdedIm);
  75.         im.copyTo(valPixels0, ~thresholdedIm);
  76.  
  77.         cv::Scalar mean1, stdDev1, mean0, stdDev0;
  78.         cv::meanStdDev(valPixels1, mean1, stdDev1);
  79.         cv::meanStdDev(valPixels0, mean0, stdDev0);
  80.  
  81.         double var1 = stdDev1[0] * stdDev1[0];
  82.         double var0 = stdDev0[0] * stdDev0[0];
  83.  
  84.         return weight0 * var0 + weight1 * var1;
  85.     }
  86.  
  87.     cv::Mat SelectThreshold(const cv::Mat& img)
  88.     {
  89.         int maxVal = 255;
  90.         std::vector<double> criterias;
  91.         for (int th = 0; th <= maxVal; ++th) {
  92.             criterias.push_back(dans1::CalculateCriteria(img, th));
  93.         }
  94.  
  95.         auto minElement = std::min_element(criterias.begin(), criterias.end());
  96.         int bestThreshold = static_cast<int>(std::distance(criterias.begin(), minElement));
  97.  
  98.         cv::Mat binary;
  99.         cv::threshold(img, binary, bestThreshold, 255, cv::THRESH_BINARY);
  100.  
  101.         return binary;
  102.     }
  103.  
  104. } // namespace original
  105.  
  106. // ===================================================================
  107. namespace dans2 {
  108.  
  109. cv::Mat SelectThreshold(const cv::Mat& img)
  110. {
  111.     int const histSize = 256;
  112.     float range[] = { 0, 256 };
  113.     const float* histRange[] = { range };
  114.  
  115.     cv::Mat hist;
  116.     cv::calcHist(&img, 1, 0, cv::Mat(), hist, 1, &histSize, histRange, true, false);
  117.     hist.convertTo(hist, CV_64FC1);
  118.  
  119.     cv::Mat hist_sums = hist.clone();
  120.     for (int i(0); i < histSize; ++i) {
  121.         hist_sums.at<double>(i) *= i;
  122.     }
  123.  
  124.     cv::Mat hist_rcumm = hist.clone();
  125.     cv::Mat hist_sums_rcumm = hist_sums.clone();
  126.  
  127.     for (int i(histSize); i > 0; --i) {
  128.         hist_rcumm.at<double>(i - 1) += hist_rcumm.at<double>(i);
  129.         hist_sums_rcumm.at<double>(i - 1) += hist_sums_rcumm.at<double>(i);
  130.     }
  131.  
  132.     cv::Mat means1 = hist_sums_rcumm / img.total();
  133.     cv::Mat means0 = (hist_sums_rcumm.at<double>(0) - hist_sums_rcumm) / img.total();
  134.  
  135.     cv::Mat var0 = cv::Mat::zeros(histSize, 1, CV_64FC1);
  136.     cv::Mat var1 = cv::Mat::zeros(histSize, 1, CV_64FC1);
  137.     for (int th(0); th < histSize; ++th) {
  138.         double mean0 = means0.at<double>(th);
  139.         double mean1 = means1.at<double>(th);
  140.         for (int i(0); i < histSize; ++i) {
  141.             if (i >= th) {
  142.                 var0.at<double>(th) += hist.at<double>(i) * (0 - mean0) * (0 - mean0);
  143.                 var1.at<double>(th) += hist.at<double>(i) * (i - mean1) * (i - mean1);
  144.             } else {
  145.                 var0.at<double>(th) += hist.at<double>(i) * (i - mean0) * (i - mean0);
  146.                 var1.at<double>(th) += hist.at<double>(i) * (0 - mean1) * (0 - mean1);
  147.             }
  148.         }
  149.     }
  150.  
  151.     var0 /= img.total();
  152.     var1 /= img.total();
  153.  
  154.     cv::Mat weights1 = hist_rcumm / img.total();
  155.     cv::Mat weights0 = 1 - weights1;
  156.  
  157.     cv::Mat criterias = weights0.mul(var0) + weights1.mul(var1);
  158.  
  159.     cv::Point minLoc;
  160.     cv::minMaxLoc(criterias, nullptr, nullptr, &minLoc);
  161.     double const bestThreshold = minLoc.y;
  162.  
  163.     cv::Mat binary;
  164.     cv::threshold(img, binary, bestThreshold, 255, cv::THRESH_BINARY);
  165.  
  166.     return binary;
  167. }
  168.  
  169. } // namespace dans2
  170.  
  171. // ===================================================================
  172.  
  173. int main(int argc, const char* argv[])
  174. {
  175.     cv::Mat src_img = cv::imread("sudoku.png", cv::IMREAD_GRAYSCALE);
  176.  
  177.     cv::Mat result_img, result_img2, result_img3;
  178.  
  179.     std::vector<size_t> times, times2, times3;
  180.     for (int i = 0; i < 16; ++i) {
  181.         {
  182.             auto start_t = std::chrono::high_resolution_clock::now();
  183.             result_img = original::SelectThreshold(src_img);
  184.             auto end_t = std::chrono::high_resolution_clock::now();
  185.             auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_t - start_t);
  186.             times.push_back(duration.count());
  187.         }
  188.  
  189.         {
  190.             auto start_t = std::chrono::high_resolution_clock::now();
  191.             result_img2 = dans1::SelectThreshold(src_img);
  192.             auto end_t = std::chrono::high_resolution_clock::now();
  193.             auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_t - start_t);
  194.             times2.push_back(duration.count());
  195.         }
  196.  
  197.         {
  198.             auto start_t = std::chrono::high_resolution_clock::now();
  199.             result_img3 = dans2::SelectThreshold(src_img);
  200.             auto end_t = std::chrono::high_resolution_clock::now();
  201.             auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_t - start_t);
  202.             times3.push_back(duration.count());
  203.         }
  204.     }
  205.  
  206.     std::sort(times.begin(), times.end());
  207.     std::sort(times2.begin(), times2.end());
  208.     std::sort(times3.begin(), times3.end());
  209.  
  210.     std::cout << times[0] << "   " << times2[0] << "   " << times3[0] << "\n";
  211.  
  212.     cv::Mat delta2, delta3;
  213.     cv::absdiff(result_img, result_img2, delta2);
  214.     cv::absdiff(result_img, result_img3, delta3);
  215.     std::cout << cv::countNonZero(delta2) << " " << cv::countNonZero(delta3) << "\n";
  216. }
  217.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement