blob: 74809d14bc4456fa679bee5f68ba82f5f282ad4c [file] [log] [blame]
Brian Silverman37b15b32019-03-10 13:30:18 -07001#include "aos/vision/blob/threshold.h"
2
Brian Silverman4482db52019-03-10 16:14:48 -07003#include "aos/logging/logging.h"
4
Brian Silverman37b15b32019-03-10 13:30:18 -07005namespace aos {
6namespace vision {
7
Brian Silverman4482db52019-03-10 16:14:48 -07008// Expands to a unique value for each combination of values for 5 bools.
Brian Silverman37b15b32019-03-10 13:30:18 -07009#define MASH(v0, v1, v2, v3, v4) \
10 ((uint8_t(v0) << 4) | (uint8_t(v1) << 3) | (uint8_t(v2) << 2) | \
11 (uint8_t(v3) << 1) | (uint8_t(v4)))
12
Brian Silverman4482db52019-03-10 16:14:48 -070013// At a high level, the algorithm is the same as the slow thresholding, except
14// it operates in 4-pixel chunks. The handling for each of these chunks is
15// manually flattened (via codegen) into a 32-case switch statement. There are
16// 2^4 cases for each pixel being in or out, along with another set of cases
17// depending on whether the start of the chunk is in a range or not.
Brian Silverman37b15b32019-03-10 13:30:18 -070018RangeImage FastYuyvYThreshold(ImageFormat fmt, const char *data,
19 uint8_t value) {
Brian Silverman4482db52019-03-10 16:14:48 -070020 CHECK_EQ(0, fmt.w % 4);
21 std::vector<std::vector<ImageRange>> result;
22 result.reserve(fmt.h);
23
24 // Iterate through each row.
Brian Silverman37b15b32019-03-10 13:30:18 -070025 for (int y = 0; y < fmt.h; ++y) {
Brian Silverman4482db52019-03-10 16:14:48 -070026 // The start of the data for the current row.
27 const char *const current_row = fmt.w * y * 2 + data;
28 bool in_range = false;
29 int current_range_start = -1;
30 std::vector<ImageRange> current_row_ranges;
31 // Iterate through each 4-pixel chunk
Brian Silverman37b15b32019-03-10 13:30:18 -070032 for (int x = 0; x < fmt.w / 4; ++x) {
Brian Silverman4482db52019-03-10 16:14:48 -070033 // The per-channel (YUYV) values in the current chunk.
34 uint8_t chunk_channels[8];
35 memcpy(&chunk_channels[0], current_row + x * 4 * 2, 8);
36 const uint8_t pattern =
37 MASH(in_range, chunk_channels[0] > value, chunk_channels[2] > value,
38 chunk_channels[4] > value, chunk_channels[6] > value);
Brian Silverman37b15b32019-03-10 13:30:18 -070039 switch (pattern) {
Brian Silverman4482db52019-03-10 16:14:48 -070040 // clang-format off
41/*
Brian Silverman37b15b32019-03-10 13:30:18 -070042# Ruby code to generate the below code:
4332.times do |v|
44 puts "case MASH(#{[v[4], v[3], v[2], v[1], v[0]].join(", ")}):"
Brian Silverman4482db52019-03-10 16:14:48 -070045 in_range = v[4]
46 current_range_start = "current_range_start"
Brian Silverman37b15b32019-03-10 13:30:18 -070047 4.times do |i|
Brian Silverman4482db52019-03-10 16:14:48 -070048 if v[3 - i] != in_range
49 if (in_range == 1)
50 puts " current_row_ranges.emplace_back(ImageRange(#{current_range_start}, x * 4 + #{i}));"
Brian Silverman37b15b32019-03-10 13:30:18 -070051 else
Brian Silverman4482db52019-03-10 16:14:48 -070052 current_range_start = "x * 4 + #{i}"
Brian Silverman37b15b32019-03-10 13:30:18 -070053 end
Brian Silverman4482db52019-03-10 16:14:48 -070054 in_range = v[3 - i]
Brian Silverman37b15b32019-03-10 13:30:18 -070055 end
56 end
Brian Silverman4482db52019-03-10 16:14:48 -070057 if (current_range_start != "current_range_start")
58 puts " current_range_start = #{current_range_start};"
Brian Silverman37b15b32019-03-10 13:30:18 -070059 end
Brian Silverman4482db52019-03-10 16:14:48 -070060 if (in_range != v[4])
61 puts " in_range = #{["false", "true"][v[0]]};"
Brian Silverman37b15b32019-03-10 13:30:18 -070062 end
63 puts " break;"
64end
65*/
Brian Silverman4482db52019-03-10 16:14:48 -070066 // clang-format on
Brian Silverman37b15b32019-03-10 13:30:18 -070067 case MASH(0, 0, 0, 0, 0):
68 break;
69 case MASH(0, 0, 0, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -070070 current_range_start = x * 4 + 3;
71 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -070072 break;
73 case MASH(0, 0, 0, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -070074 current_row_ranges.emplace_back(ImageRange(x * 4 + 2, x * 4 + 3));
75 current_range_start = x * 4 + 2;
Brian Silverman37b15b32019-03-10 13:30:18 -070076 break;
77 case MASH(0, 0, 0, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -070078 current_range_start = x * 4 + 2;
79 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -070080 break;
81 case MASH(0, 0, 1, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -070082 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 2));
83 current_range_start = x * 4 + 1;
Brian Silverman37b15b32019-03-10 13:30:18 -070084 break;
85 case MASH(0, 0, 1, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -070086 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 2));
87 current_range_start = x * 4 + 3;
88 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -070089 break;
90 case MASH(0, 0, 1, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -070091 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 3));
92 current_range_start = x * 4 + 1;
Brian Silverman37b15b32019-03-10 13:30:18 -070093 break;
94 case MASH(0, 0, 1, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -070095 current_range_start = x * 4 + 1;
96 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -070097 break;
98 case MASH(0, 1, 0, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -070099 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 1));
100 current_range_start = x * 4 + 0;
Brian Silverman37b15b32019-03-10 13:30:18 -0700101 break;
102 case MASH(0, 1, 0, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700103 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 1));
104 current_range_start = x * 4 + 3;
105 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -0700106 break;
107 case MASH(0, 1, 0, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700108 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 1));
109 current_row_ranges.emplace_back(ImageRange(x * 4 + 2, x * 4 + 3));
110 current_range_start = x * 4 + 2;
Brian Silverman37b15b32019-03-10 13:30:18 -0700111 break;
112 case MASH(0, 1, 0, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700113 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 1));
114 current_range_start = x * 4 + 2;
115 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -0700116 break;
117 case MASH(0, 1, 1, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700118 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 2));
119 current_range_start = x * 4 + 0;
Brian Silverman37b15b32019-03-10 13:30:18 -0700120 break;
121 case MASH(0, 1, 1, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700122 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 2));
123 current_range_start = x * 4 + 3;
124 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -0700125 break;
126 case MASH(0, 1, 1, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700127 current_row_ranges.emplace_back(ImageRange(x * 4 + 0, x * 4 + 3));
128 current_range_start = x * 4 + 0;
Brian Silverman37b15b32019-03-10 13:30:18 -0700129 break;
130 case MASH(0, 1, 1, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700131 current_range_start = x * 4 + 0;
132 in_range = true;
Brian Silverman37b15b32019-03-10 13:30:18 -0700133 break;
134 case MASH(1, 0, 0, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700135 current_row_ranges.emplace_back(
136 ImageRange(current_range_start, x * 4 + 0));
137 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700138 break;
139 case MASH(1, 0, 0, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700140 current_row_ranges.emplace_back(
141 ImageRange(current_range_start, x * 4 + 0));
142 current_range_start = x * 4 + 3;
Brian Silverman37b15b32019-03-10 13:30:18 -0700143 break;
144 case MASH(1, 0, 0, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700145 current_row_ranges.emplace_back(
146 ImageRange(current_range_start, x * 4 + 0));
147 current_row_ranges.emplace_back(ImageRange(x * 4 + 2, x * 4 + 3));
148 current_range_start = x * 4 + 2;
149 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700150 break;
151 case MASH(1, 0, 0, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700152 current_row_ranges.emplace_back(
153 ImageRange(current_range_start, x * 4 + 0));
154 current_range_start = x * 4 + 2;
Brian Silverman37b15b32019-03-10 13:30:18 -0700155 break;
156 case MASH(1, 0, 1, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700157 current_row_ranges.emplace_back(
158 ImageRange(current_range_start, x * 4 + 0));
159 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 2));
160 current_range_start = x * 4 + 1;
161 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700162 break;
163 case MASH(1, 0, 1, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700164 current_row_ranges.emplace_back(
165 ImageRange(current_range_start, x * 4 + 0));
166 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 2));
167 current_range_start = x * 4 + 3;
Brian Silverman37b15b32019-03-10 13:30:18 -0700168 break;
169 case MASH(1, 0, 1, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700170 current_row_ranges.emplace_back(
171 ImageRange(current_range_start, x * 4 + 0));
172 current_row_ranges.emplace_back(ImageRange(x * 4 + 1, x * 4 + 3));
173 current_range_start = x * 4 + 1;
174 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700175 break;
176 case MASH(1, 0, 1, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700177 current_row_ranges.emplace_back(
178 ImageRange(current_range_start, x * 4 + 0));
179 current_range_start = x * 4 + 1;
Brian Silverman37b15b32019-03-10 13:30:18 -0700180 break;
181 case MASH(1, 1, 0, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700182 current_row_ranges.emplace_back(
183 ImageRange(current_range_start, x * 4 + 1));
184 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700185 break;
186 case MASH(1, 1, 0, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700187 current_row_ranges.emplace_back(
188 ImageRange(current_range_start, x * 4 + 1));
189 current_range_start = x * 4 + 3;
Brian Silverman37b15b32019-03-10 13:30:18 -0700190 break;
191 case MASH(1, 1, 0, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700192 current_row_ranges.emplace_back(
193 ImageRange(current_range_start, x * 4 + 1));
194 current_row_ranges.emplace_back(ImageRange(x * 4 + 2, x * 4 + 3));
195 current_range_start = x * 4 + 2;
196 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700197 break;
198 case MASH(1, 1, 0, 1, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700199 current_row_ranges.emplace_back(
200 ImageRange(current_range_start, x * 4 + 1));
201 current_range_start = x * 4 + 2;
Brian Silverman37b15b32019-03-10 13:30:18 -0700202 break;
203 case MASH(1, 1, 1, 0, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700204 current_row_ranges.emplace_back(
205 ImageRange(current_range_start, x * 4 + 2));
206 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700207 break;
208 case MASH(1, 1, 1, 0, 1):
Brian Silverman4482db52019-03-10 16:14:48 -0700209 current_row_ranges.emplace_back(
210 ImageRange(current_range_start, x * 4 + 2));
211 current_range_start = x * 4 + 3;
Brian Silverman37b15b32019-03-10 13:30:18 -0700212 break;
213 case MASH(1, 1, 1, 1, 0):
Brian Silverman4482db52019-03-10 16:14:48 -0700214 current_row_ranges.emplace_back(
215 ImageRange(current_range_start, x * 4 + 3));
216 in_range = false;
Brian Silverman37b15b32019-03-10 13:30:18 -0700217 break;
218 case MASH(1, 1, 1, 1, 1):
219 break;
220 }
Brian Silverman37b15b32019-03-10 13:30:18 -0700221 }
Brian Silverman4482db52019-03-10 16:14:48 -0700222 if (in_range) {
223 current_row_ranges.emplace_back(ImageRange(current_range_start, fmt.w));
Brian Silverman37b15b32019-03-10 13:30:18 -0700224 }
Brian Silverman4482db52019-03-10 16:14:48 -0700225 result.push_back(current_row_ranges);
Brian Silverman37b15b32019-03-10 13:30:18 -0700226 }
Brian Silverman4482db52019-03-10 16:14:48 -0700227 return RangeImage(0, std::move(result));
Brian Silverman37b15b32019-03-10 13:30:18 -0700228}
229
230#undef MASH
231
232} // namespace vision
233} // namespace aos