Add a test for FastGaussian

I had this written, but forgot to commit it before.

Change-Id: I0e482f2bc2b90b92875f6dffa63471ebd52e6cb3
diff --git a/y2020/vision/sift/fast_gaussian_test.cc b/y2020/vision/sift/fast_gaussian_test.cc
new file mode 100644
index 0000000..e62f26e
--- /dev/null
+++ b/y2020/vision/sift/fast_gaussian_test.cc
@@ -0,0 +1,75 @@
+#include "y2020/vision/sift/fast_gaussian.h"
+
+#include <opencv2/imgproc.hpp>
+#include "gtest/gtest.h"
+
+#include "y2020/vision/sift/fast_gaussian_all.h"
+
+namespace frc971 {
+namespace vision {
+namespace testing {
+
+class FastGaussianTest : public ::testing::Test {
+ public:
+  cv::Mat RandomImage(int width = 500, int height = 500, int type = CV_8UC3) {
+    cv::Mat result(width, height, type);
+    cv::randu(result, 0, 255);
+    return result;
+  }
+
+  void ExpectEqual(const cv::Mat &a, const cv::Mat &b, double epsilon = 1e-10) {
+    const cv::Mat difference = a - b;
+    double min, max;
+    cv::minMaxLoc(difference, &min, &max);
+    EXPECT_GE(min, -epsilon);
+    EXPECT_LE(max, epsilon);
+  }
+};
+
+// Verifies that the default GaussianBlur parameters work out to 15x15 with
+// sigma of 1.6.
+TEST_F(FastGaussianTest, DefaultGaussianSize) {
+  const auto image = RandomImage(500, 500, CV_32FC3);
+  cv::Mat default_blurred, explicitly_blurred;
+  cv::GaussianBlur(image, default_blurred, cv::Size(), 1.6, 1.6);
+  cv::GaussianBlur(image, explicitly_blurred, cv::Size(15, 15), 1.6, 1.6);
+  ExpectEqual(default_blurred, explicitly_blurred);
+}
+
+// Verifies that with 8U just a 9x9 blur is as much as you get.
+TEST_F(FastGaussianTest, GaussianSizeS8) {
+  const auto image = RandomImage(500, 500, CV_8UC3);
+  cv::Mat big_blurred, little_blurred;
+  cv::GaussianBlur(image, big_blurred, cv::Size(15, 15), 1.6, 1.6);
+  cv::GaussianBlur(image, little_blurred, cv::Size(9, 9), 1.6, 1.6);
+  ExpectEqual(big_blurred, little_blurred);
+}
+
+// Verifies that FastGaussian and cv::GaussianBlur give the same result.
+TEST_F(FastGaussianTest, FastGaussian) {
+  const auto image = RandomImage(360, 640, CV_16SC1);
+  cv::Mat slow, fast, fast_direct;
+  static constexpr double kSigma = 1.9465878414647133;
+  static constexpr int kSize = 13;
+
+  cv::GaussianBlur(image, slow, cv::Size(kSize, kSize), kSigma, kSigma);
+  FastGaussian(image, &fast, kSigma);
+
+  // Explicitly call the generated code, to verify that our chosen parameters do
+  // in fact result in using the generated one.
+  fast_direct.create(slow.size(), slow.type());
+  ASSERT_EQ(0,
+            DoGeneratedFastGaussian(MatToHalide<const int16_t>(image),
+                                    MatToHalide<int16_t>(fast_direct), kSigma));
+
+
+  // 50/65536 = 0.00076, which is under 1%, which is pretty close.
+  ExpectEqual(slow, fast, 50);
+  // The wrapper should be calling the exact same code, so it should end up with
+  // the exact same result.
+  ExpectEqual(fast, fast_direct, 0);
+}
+
+}  // namespace testing
+}  // namespace vision
+}  // namespace frc971