blob: 22549ac10c6d1d66fe09244c674a92e37833a346 [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
9namespace frc971 {
10namespace vision {
11namespace {
12
13void 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.
22constexpr 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.
26constexpr 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.
33constexpr int kMinWarnSize = 80;
34
35bool IsSmall(cv::Size size) {
36 return size.height <= kMinWarnSize && size.width <= kMinWarnSize;
37}
38
39} // namespace
40
41void 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
69void 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
95void 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