blob: 108da35a3feabd20a7d80701f0e8362371f62773 [file] [log] [blame]
Brian Silverman5eec8b92019-03-10 15:14:31 -07001#include "aos/vision/blob/threshold.h"
2
Brian Silverman4482db52019-03-10 16:14:48 -07003#include <random>
Brian Silverman5eec8b92019-03-10 15:14:31 -07004#include <vector>
5
6#include "aos/vision/blob/range_image.h"
7#include "aos/vision/image/image_types.h"
8#include "gmock/gmock.h"
9#include "gtest/gtest.h"
10
11namespace aos {
12namespace vision {
13namespace testing {
14
15class YuyvYThresholdTest : public ::testing::Test {
Brian Silverman4482db52019-03-10 16:14:48 -070016 public:
17 std::vector<char> RandomImage(ImageFormat format) {
18 std::vector<char> result;
19 result.resize(format.w * format.h * 2);
20 std::uniform_int_distribution<char> distribution(
21 std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
22 for (size_t i = 0; i < result.size(); ++i) {
23 result[i] = distribution(generator_);
24 }
25 return result;
26 }
27
28 private:
29 std::minstd_rand generator_;
Brian Silverman5eec8b92019-03-10 15:14:31 -070030};
31
32// Verifies that a simple image is thresholded correctly.
33//
34// Specifically, we want to get this result from the thresholding:
Brian Silverman4482db52019-03-10 16:14:48 -070035// --+-----
36// +------+
37// -++++++-
38// +++-++++
39// --------
40// ++++-+++
41// ++++++++
42// +-+-+--+
Brian Silverman5eec8b92019-03-10 15:14:31 -070043TEST_F(YuyvYThresholdTest, SimpleImage) {
44 ImageFormat format;
Brian Silverman4482db52019-03-10 16:14:48 -070045 format.w = 8;
Brian Silverman5eec8b92019-03-10 15:14:31 -070046 format.h = 8;
47
48 std::vector<std::vector<ImageRange>> expected_ranges;
49 std::vector<char> image;
Brian Silverman4482db52019-03-10 16:14:48 -070050 image.resize(8 * 8 * 2);
51 // --+-----
52 image[0 * 2 + 0 * 16] = 0;
53 image[1 * 2 + 0 * 16] = 0;
54 image[2 * 2 + 0 * 16] = 128;
55 image[3 * 2 + 0 * 16] = 127;
56 image[4 * 2 + 0 * 16] = 0;
57 image[5 * 2 + 0 * 16] = 0;
58 image[6 * 2 + 0 * 16] = 0;
59 image[7 * 2 + 0 * 16] = 0;
Brian Silverman5eec8b92019-03-10 15:14:31 -070060 expected_ranges.push_back({{{2, 3}}});
Brian Silverman4482db52019-03-10 16:14:48 -070061 // +------+
62 image[0 * 2 + 1 * 16] = 128;
63 image[1 * 2 + 1 * 16] = 0;
64 image[2 * 2 + 1 * 16] = 0;
65 image[3 * 2 + 1 * 16] = 10;
66 image[4 * 2 + 1 * 16] = 30;
67 image[5 * 2 + 1 * 16] = 50;
68 image[6 * 2 + 1 * 16] = 70;
69 image[7 * 2 + 1 * 16] = 255;
70 expected_ranges.push_back({{{0, 1}, {7, 8}}});
71 // -++++++-
72 image[0 * 2 + 2 * 16] = 73;
73 image[1 * 2 + 2 * 16] = 246;
74 image[2 * 2 + 2 * 16] = 247;
75 image[3 * 2 + 2 * 16] = 248;
76 image[4 * 2 + 2 * 16] = 249;
77 image[5 * 2 + 2 * 16] = 250;
78 image[6 * 2 + 2 * 16] = 250;
79 image[7 * 2 + 2 * 16] = 45;
80 expected_ranges.push_back({{{1, 7}}});
81 // +++-++++
82 image[0 * 2 + 3 * 16] = 128;
83 image[1 * 2 + 3 * 16] = 134;
84 image[2 * 2 + 3 * 16] = 250;
85 image[3 * 2 + 3 * 16] = 0;
86 image[4 * 2 + 3 * 16] = 230;
87 image[5 * 2 + 3 * 16] = 230;
88 image[6 * 2 + 3 * 16] = 230;
89 image[7 * 2 + 3 * 16] = 210;
90 expected_ranges.push_back({{{0, 3}, {4, 8}}});
91 // --------
92 image[0 * 2 + 4 * 16] = 7;
93 image[1 * 2 + 4 * 16] = 120;
94 image[2 * 2 + 4 * 16] = 127;
95 image[3 * 2 + 4 * 16] = 0;
96 image[4 * 2 + 4 * 16] = 50;
97 image[5 * 2 + 4 * 16] = 80;
98 image[6 * 2 + 4 * 16] = 110;
99 image[7 * 2 + 4 * 16] = 25;
Brian Silverman5eec8b92019-03-10 15:14:31 -0700100 expected_ranges.push_back({{}});
Brian Silverman4482db52019-03-10 16:14:48 -0700101 // ++++-+++
102 image[0 * 2 + 5 * 16] = 140;
103 image[1 * 2 + 5 * 16] = 140;
104 image[2 * 2 + 5 * 16] = 140;
105 image[3 * 2 + 5 * 16] = 140;
106 image[4 * 2 + 5 * 16] = 0;
107 image[5 * 2 + 5 * 16] = 140;
108 image[6 * 2 + 5 * 16] = 140;
109 image[7 * 2 + 5 * 16] = 140;
110 expected_ranges.push_back({{{0, 4}, {5, 8}}});
111 // ++++++++
112 image[0 * 2 + 6 * 16] = 128;
113 image[1 * 2 + 6 * 16] = 128;
114 image[2 * 2 + 6 * 16] = 128;
115 image[3 * 2 + 6 * 16] = 128;
116 image[4 * 2 + 6 * 16] = 128;
117 image[5 * 2 + 6 * 16] = 128;
118 image[6 * 2 + 6 * 16] = 128;
119 image[7 * 2 + 6 * 16] = 128;
120 expected_ranges.push_back({{{0, 8}}});
121 // +-+-+--+
122 image[0 * 2 + 7 * 16] = 200;
123 image[1 * 2 + 7 * 16] = 0;
124 image[2 * 2 + 7 * 16] = 200;
125 image[3 * 2 + 7 * 16] = 0;
126 image[4 * 2 + 7 * 16] = 200;
127 image[5 * 2 + 7 * 16] = 0;
128 image[6 * 2 + 7 * 16] = 0;
129 image[7 * 2 + 7 * 16] = 200;
130 expected_ranges.push_back({{{0, 1}, {2, 3}, {4, 5}, {7, 8}}});
Brian Silverman5eec8b92019-03-10 15:14:31 -0700131 const RangeImage expected_result(0, std::move(expected_ranges));
132
133 const auto slow_result = SlowYuyvYThreshold(format, image.data(), 127);
134 ASSERT_EQ(expected_result, slow_result);
Brian Silverman4482db52019-03-10 16:14:48 -0700135 const auto fast_result = FastYuyvYThreshold(format, image.data(), 127);
136 ASSERT_EQ(expected_result, fast_result);
137}
138
139// Verifies that a couple of completely random images match.
140TEST_F(YuyvYThresholdTest, Random) {
141 for (int i = 0; i < 10; ++i) {
142 ImageFormat small_format;
143 small_format.w = 16;
144 small_format.h = 16;
145 const auto small_image = RandomImage(small_format);
146 const auto slow_result =
147 SlowYuyvYThreshold(small_format, small_image.data(), 127);
148 const auto fast_result =
149 FastYuyvYThreshold(small_format, small_image.data(), 127);
150 ASSERT_EQ(slow_result, fast_result);
151 }
152 for (int i = 0; i < 10; ++i) {
153 ImageFormat large_format;
154 large_format.w = 1024;
155 large_format.h = 512;
156 const auto large_image = RandomImage(large_format);
157 const auto slow_result =
158 SlowYuyvYThreshold(large_format, large_image.data(), 127);
159 const auto fast_result =
160 FastYuyvYThreshold(large_format, large_image.data(), 127);
161 ASSERT_EQ(slow_result, fast_result);
162 }
163}
164
165// Verifies that changing the U and V values doesn't affect the result.
166TEST_F(YuyvYThresholdTest, UVIgnored) {
167 ImageFormat format;
168 format.w = 32;
169 format.h = 20;
170 const auto baseline_image = RandomImage(format);
171 const auto baseline_result =
172 SlowYuyvYThreshold(format, baseline_image.data(), 127);
173 for (int i = 0; i < 5; ++i) {
174 auto tweaked_image = RandomImage(format);
175 for (int y = 0; y < format.h; ++y) {
176 for (int x = 0; x < format.w; ++x) {
177 tweaked_image[x * 2 + y * format.w * 2] =
178 baseline_image[x * 2 + y * format.w * 2];
179 }
180 }
181
182 const auto slow_result =
183 SlowYuyvYThreshold(format, tweaked_image.data(), 127);
184 ASSERT_EQ(baseline_result, slow_result);
185 const auto fast_result =
186 FastYuyvYThreshold(format, tweaked_image.data(), 127);
187 ASSERT_EQ(baseline_result, fast_result);
188 }
Brian Silverman5eec8b92019-03-10 15:14:31 -0700189}
190
191} // namespace testing
192} // namespace vision
193} // namespace aos