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