Advertisement
dan-masek

Average Filter by MicMac on SO - fixing it for grayscale

Feb 22nd, 2022
1,779
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.80 KB | None | 0 0
  1. #include <opencv2/opencv.hpp>
  2.  
  3. /*
  4. Note: I split off this piece of code into a separate function in order
  5.       to simplify the reasoning about the code.
  6.       This is probably not ideal for performance, but it's too early to worry about that now.
  7. Note: Synced the meaning of x and y (and related variables) with changes in filter_mean.
  8. Note: Added a count variable as a trivial way to keep track of divisor for mean calculation.
  9. Note: Fixed the missing division in calculation of the mean.
  10. Note: Changed the mean calculation to use floating point numbers and added
  11.       rounding to nearest integer. This seems like a nicer way to get the mean.
  12. Note: Added a check to make sure we're only reading valid pixels.
  13.       In other words, avoid reading values outside the bounds of the input image.
  14.       This is needed to handle processing pixels near the edge of the input image.
  15. Note: You didn't iterate over the whole window. We need delta x/y to range
  16.       from -framing to +framing inclusive.
  17.       Again it's better to iterate rows before columns due to memory layout.
  18. */
  19. uint8_t filter_mean_at(cv::Mat const& image, int32_t x, int32_t y, int32_t framing)
  20. {
  21.     std::cout << "Applying filter at (" << x << "," << y << ")\n";
  22.     int32_t sum{ 0 };
  23.     int32_t count{ 0 };
  24.     for (int32_t dy = -framing; dy <= framing; ++dy) {
  25.         for (int32_t dx = -framing; dx <= framing; ++dx) {        
  26.             int32_t const xx = x + dx;
  27.             int32_t const yy = y + dy;
  28.             if ((xx >= 0) && (xx < image.cols) && (yy >= 0) && (yy < image.rows)) {
  29.                 std::cout << " * Processing pixel at (" << xx << "," << yy << ")\n";
  30.                 sum += image.at<uint8_t>(yy, xx);
  31.             } else {
  32.                 std::cout << " * Skipping pixel at (" << xx << "," << yy << ")\n";
  33.             }
  34.             ++count;
  35.         }
  36.     }
  37.  
  38.     int32_t mean = cvRound(static_cast<double>(sum) / count);
  39.     std::cout << " Result = " << mean << " (as uint8_t = "
  40.         << static_cast<int32_t>(static_cast<uint8_t>(mean)) << ")\n";
  41.     return mean;
  42. }
  43.  
  44. /*
  45. Note: Since this is only expected to work with positive and odd window sizes
  46.       we should enforce that. Simple assert will do for now.
  47. Note: We also expect this to work only with 8-bit unsigned images with either
  48.       one (grayscale) or three (BGR, RGB, whatever) channels. Assert added.
  49. Note: Cloning the input image to result is unnecessary, since we intend
  50.       to overwrite all the values anyway. It might make debugging harder too.
  51.       Explicitly initializing the Mat to zeros is good enough.
  52. Note: Due to how the pixels are arranged in the buffer, it's bound to be more
  53.       effective to have outer loop iterate over rows. That way you access
  54.       memory locations in sequence. I swapped the two loops.
  55. Note: You used x to refer to rows and y to refer to columns. That's unexpected.
  56.       I switched them around to the conventional usage.
  57. */
  58. cv::Mat filter_mean(cv::Mat image, int window_size)
  59. {
  60.     assert((window_size > 0) && (window_size % 2 == 1));
  61.     assert((image.type() == CV_8UC1) || (image.type() == CV_8UC3));
  62.  
  63.     cv::Mat result = cv::Mat::zeros(image.rows, image.cols, image.type());
  64.  
  65.     int32_t const framing = window_size / 2;
  66.     for (int32_t y = 0; y < image.rows; ++y) {
  67.         for (int32_t x = 0; x < image.cols; ++x) {
  68.             result.at<uint8_t>(y, x) = filter_mean_at(image, x, y, framing);
  69.         }
  70.     }
  71.     return result;
  72. }
  73.  
  74. int main()
  75. {
  76.     // Just some small simple 4x4 grayscale image to test this on...
  77.     cv::Mat img = (cv::Mat1b(4, 4)
  78.         << 0, 16, 32, 48
  79.         , 64, 64, 64, 64
  80.         , 128, 128, 128, 192
  81.         , 255, 255, 255, 255
  82.         );
  83.  
  84.     cv::Mat filtered_image = filter_mean(img, 3);
  85.    
  86.     std::cout << "Result:\n" << filtered_image << '\n';
  87.  
  88.     return 0;
  89. }
  90.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement