blob: 69432b48412bcf8f809acef65cb124dc6365f181 [file] [log] [blame]
Brian Silverman3fec6482020-01-19 17:56:20 -08001#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 Pleinesf63bde82024-01-13 15:59:33 -08009namespace frc971::vision {
Brian Silverman3fec6482020-01-19 17:56:20 -080010namespace {
11
12void 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.
21constexpr 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.
25constexpr 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.
32constexpr int kMinWarnSize = 80;
33
34bool IsSmall(cv::Size size) {
35 return size.height <= kMinWarnSize && size.width <= kMinWarnSize;
36}
37
38} // namespace
39
40void 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
68void 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
94void 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 Pleinesf63bde82024-01-13 15:59:33 -0800124} // namespace frc971::vision