Brian Silverman | 3fec648 | 2020-01-19 17:56:20 -0800 | [diff] [blame] | 1 | #include "y2020/vision/sift/fast_gaussian.h" |
| 2 | |
| 3 | #include <iomanip> |
| 4 | |
| 5 | #include <opencv2/imgproc.hpp> |
| 6 | |
| 7 | #include "y2020/vision/sift/fast_gaussian_all.h" |
| 8 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame^] | 9 | namespace frc971::vision { |
Brian Silverman | 3fec648 | 2020-01-19 17:56:20 -0800 | [diff] [blame] | 10 | namespace { |
| 11 | |
| 12 | void CheckNonOverlapping(const cv::Mat &a, const cv::Mat &b) { |
| 13 | CHECK(a.data > b.data + b.total() * b.elemSize() || a.data < b.data) |
| 14 | << ": images may not overlap"; |
| 15 | CHECK(b.data > a.data + a.total() * a.elemSize() || b.data < a.data) |
| 16 | << ": images may not overlap"; |
| 17 | } |
| 18 | |
| 19 | // An easy toggle to always fall back to the slow implementations, to verify the |
| 20 | // results are the same. |
| 21 | constexpr bool kUseFast = true; |
| 22 | |
| 23 | // An easy toggle to print the result of all operations, for verifying that the |
| 24 | // halide code is doing what we expect. |
| 25 | constexpr bool kPrintAll = false; |
| 26 | |
| 27 | // We deliberately don't generate code for images smaller than this, so don't |
| 28 | // print warnings about them. |
| 29 | // |
| 30 | // The opencv implementations are so fast below this size, the build time to |
| 31 | // generate halide versions isn't worthwhile. |
| 32 | constexpr int kMinWarnSize = 80; |
| 33 | |
| 34 | bool IsSmall(cv::Size size) { |
| 35 | return size.height <= kMinWarnSize && size.width <= kMinWarnSize; |
| 36 | } |
| 37 | |
| 38 | } // namespace |
| 39 | |
| 40 | void FastGaussian(const cv::Mat &source, cv::Mat *destination, double sigma) { |
| 41 | CHECK_EQ(source.type(), CV_16SC1); |
| 42 | |
| 43 | destination->create(source.size(), source.type()); |
| 44 | CheckNonOverlapping(source, *destination); |
| 45 | |
| 46 | int result = 1; |
| 47 | if (kUseFast) { |
| 48 | result = DoGeneratedFastGaussian(MatToHalide<const int16_t>(source), |
| 49 | MatToHalide<int16_t>(*destination), sigma); |
| 50 | } |
| 51 | if (kPrintAll) { |
| 52 | LOG(INFO) << result << ": " << source.rows << " " << source.cols << " " |
| 53 | << std::setprecision(17) << sigma; |
| 54 | } |
| 55 | if (result == 0) { |
| 56 | return; |
| 57 | } |
| 58 | if (!IsSmall(source.size())) { |
| 59 | LOG(WARNING) << "slow gaussian blur: " << source.rows << " " << source.cols |
| 60 | << " " << std::setprecision(17) << sigma; |
| 61 | } |
| 62 | CHECK_EQ(result, 1); |
| 63 | |
| 64 | cv::GaussianBlur(source, *destination, cv::Size(), sigma, sigma, |
| 65 | cv::BORDER_REPLICATE); |
| 66 | } |
| 67 | |
| 68 | void FastSubtract(const cv::Mat &a, const cv::Mat &b, cv::Mat *destination) { |
| 69 | CHECK(a.size() == b.size()); |
| 70 | destination->create(a.size(), a.type()); |
| 71 | CheckNonOverlapping(a, *destination); |
| 72 | CheckNonOverlapping(b, *destination); |
| 73 | |
| 74 | int result = 1; |
| 75 | if (kUseFast) { |
| 76 | result = DoGeneratedFastSubtract(MatToHalide<const int16_t>(a), |
| 77 | MatToHalide<const int16_t>(b), |
| 78 | MatToHalide<int16_t>(*destination)); |
| 79 | } |
| 80 | if (kPrintAll) { |
| 81 | LOG(INFO) << result << ": " << a.rows << " " << a.cols; |
| 82 | } |
| 83 | if (result == 0) { |
| 84 | return; |
| 85 | } |
| 86 | if (!IsSmall(a.size())) { |
| 87 | LOG(WARNING) << "slow subtract: " << a.rows << " " << a.cols; |
| 88 | } |
| 89 | CHECK_EQ(result, 1); |
| 90 | |
| 91 | cv::subtract(a, b, *destination); |
| 92 | } |
| 93 | |
| 94 | void FastGaussianAndSubtract(const cv::Mat &source, cv::Mat *blurred, |
| 95 | cv::Mat *difference, double sigma) { |
| 96 | CHECK_EQ(source.type(), CV_16SC1); |
| 97 | blurred->create(source.size(), source.type()); |
| 98 | difference->create(source.size(), source.type()); |
| 99 | |
| 100 | int result = 1; |
| 101 | if (kUseFast) { |
| 102 | result = DoGeneratedFastGaussianAndSubtract( |
| 103 | MatToHalide<const int16_t>(source), MatToHalide<int16_t>(*blurred), |
| 104 | MatToHalide<int16_t>(*difference), sigma); |
| 105 | } |
| 106 | if (kPrintAll) { |
| 107 | LOG(INFO) << result << ": " << source.rows << " " << source.cols << " " |
| 108 | << std::setprecision(17) << sigma; |
| 109 | } |
| 110 | if (result == 0) { |
| 111 | return; |
| 112 | } |
| 113 | if (!IsSmall(source.size())) { |
| 114 | LOG(WARNING) << "slow gaussian blur: " << source.rows << " " << source.cols |
| 115 | << " " << std::setprecision(17) << sigma; |
| 116 | } |
| 117 | CHECK_EQ(result, 1); |
| 118 | |
| 119 | cv::GaussianBlur(source, *blurred, cv::Size(), sigma, sigma, |
| 120 | cv::BORDER_REPLICATE); |
| 121 | cv::subtract(*blurred, source, *difference); |
| 122 | } |
| 123 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame^] | 124 | } // namespace frc971::vision |