blob: 3bbef1d1abb8e7f54435e2e9679bce62132e57a9 [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 // --+-----
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 image[0 * 2 + 0 * 16] = static_cast<char>(0);
53 image[1 * 2 + 0 * 16] = static_cast<char>(0);
54 image[2 * 2 + 0 * 16] = static_cast<char>(128);
55 image[3 * 2 + 0 * 16] = static_cast<char>(127);
56 image[4 * 2 + 0 * 16] = static_cast<char>(0);
57 image[5 * 2 + 0 * 16] = static_cast<char>(0);
58 image[6 * 2 + 0 * 16] = static_cast<char>(0);
59 image[7 * 2 + 0 * 16] = static_cast<char>(0);
Brian Silverman5eec8b92019-03-10 15:14:31 -070060 expected_ranges.push_back({{{2, 3}}});
Brian Silverman4482db52019-03-10 16:14:48 -070061 // +------+
Alex Perrycb7da4b2019-08-28 19:35:56 -070062 image[0 * 2 + 1 * 16] = static_cast<char>(128);
63 image[1 * 2 + 1 * 16] = static_cast<char>(0);
64 image[2 * 2 + 1 * 16] = static_cast<char>(0);
65 image[3 * 2 + 1 * 16] = static_cast<char>(10);
66 image[4 * 2 + 1 * 16] = static_cast<char>(30);
67 image[5 * 2 + 1 * 16] = static_cast<char>(50);
68 image[6 * 2 + 1 * 16] = static_cast<char>(70);
69 image[7 * 2 + 1 * 16] = static_cast<char>(255);
Brian Silverman4482db52019-03-10 16:14:48 -070070 expected_ranges.push_back({{{0, 1}, {7, 8}}});
71 // -++++++-
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 image[0 * 2 + 2 * 16] = static_cast<char>(73);
73 image[1 * 2 + 2 * 16] = static_cast<char>(246);
74 image[2 * 2 + 2 * 16] = static_cast<char>(247);
75 image[3 * 2 + 2 * 16] = static_cast<char>(248);
76 image[4 * 2 + 2 * 16] = static_cast<char>(249);
77 image[5 * 2 + 2 * 16] = static_cast<char>(250);
78 image[6 * 2 + 2 * 16] = static_cast<char>(250);
79 image[7 * 2 + 2 * 16] = static_cast<char>(45);
Brian Silverman4482db52019-03-10 16:14:48 -070080 expected_ranges.push_back({{{1, 7}}});
81 // +++-++++
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 image[0 * 2 + 3 * 16] = static_cast<char>(128);
83 image[1 * 2 + 3 * 16] = static_cast<char>(134);
84 image[2 * 2 + 3 * 16] = static_cast<char>(250);
85 image[3 * 2 + 3 * 16] = static_cast<char>(0);
86 image[4 * 2 + 3 * 16] = static_cast<char>(230);
87 image[5 * 2 + 3 * 16] = static_cast<char>(230);
88 image[6 * 2 + 3 * 16] = static_cast<char>(230);
89 image[7 * 2 + 3 * 16] = static_cast<char>(210);
Brian Silverman4482db52019-03-10 16:14:48 -070090 expected_ranges.push_back({{{0, 3}, {4, 8}}});
91 // --------
Alex Perrycb7da4b2019-08-28 19:35:56 -070092 image[0 * 2 + 4 * 16] = static_cast<char>(7);
93 image[1 * 2 + 4 * 16] = static_cast<char>(120);
94 image[2 * 2 + 4 * 16] = static_cast<char>(127);
95 image[3 * 2 + 4 * 16] = static_cast<char>(0);
96 image[4 * 2 + 4 * 16] = static_cast<char>(50);
97 image[5 * 2 + 4 * 16] = static_cast<char>(80);
98 image[6 * 2 + 4 * 16] = static_cast<char>(110);
99 image[7 * 2 + 4 * 16] = static_cast<char>(25);
Brian Silverman5eec8b92019-03-10 15:14:31 -0700100 expected_ranges.push_back({{}});
Brian Silverman4482db52019-03-10 16:14:48 -0700101 // ++++-+++
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 image[0 * 2 + 5 * 16] = static_cast<char>(140);
103 image[1 * 2 + 5 * 16] = static_cast<char>(140);
104 image[2 * 2 + 5 * 16] = static_cast<char>(140);
105 image[3 * 2 + 5 * 16] = static_cast<char>(140);
106 image[4 * 2 + 5 * 16] = static_cast<char>(0);
107 image[5 * 2 + 5 * 16] = static_cast<char>(140);
108 image[6 * 2 + 5 * 16] = static_cast<char>(140);
109 image[7 * 2 + 5 * 16] = static_cast<char>(140);
Brian Silverman4482db52019-03-10 16:14:48 -0700110 expected_ranges.push_back({{{0, 4}, {5, 8}}});
111 // ++++++++
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112 image[0 * 2 + 6 * 16] = static_cast<char>(128);
113 image[1 * 2 + 6 * 16] = static_cast<char>(128);
114 image[2 * 2 + 6 * 16] = static_cast<char>(128);
115 image[3 * 2 + 6 * 16] = static_cast<char>(128);
116 image[4 * 2 + 6 * 16] = static_cast<char>(128);
117 image[5 * 2 + 6 * 16] = static_cast<char>(128);
118 image[6 * 2 + 6 * 16] = static_cast<char>(128);
119 image[7 * 2 + 6 * 16] = static_cast<char>(128);
Brian Silverman4482db52019-03-10 16:14:48 -0700120 expected_ranges.push_back({{{0, 8}}});
121 // +-+-+--+
Alex Perrycb7da4b2019-08-28 19:35:56 -0700122 image[0 * 2 + 7 * 16] = static_cast<char>(200);
123 image[1 * 2 + 7 * 16] = static_cast<char>(0);
124 image[2 * 2 + 7 * 16] = static_cast<char>(200);
125 image[3 * 2 + 7 * 16] = static_cast<char>(0);
126 image[4 * 2 + 7 * 16] = static_cast<char>(200);
127 image[5 * 2 + 7 * 16] = static_cast<char>(0);
128 image[6 * 2 + 7 * 16] = static_cast<char>(0);
129 image[7 * 2 + 7 * 16] = static_cast<char>(200);
Brian Silverman4482db52019-03-10 16:14:48 -0700130 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