blob: c638d40bc86d66e95a15dcd851644e2e37eeaca7 [file] [log] [blame]
Eino-Ville Talvalaf2e37092020-01-07 15:32:32 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_NDEBUG 0
18#define LOG_TAG "RotateAndCropMapperTest"
19
20#include <functional>
21#include <random>
22
23#include <gtest/gtest.h>
24#include <gmock/gmock.h>
25
26#include "../device3/RotateAndCropMapper.h"
27
28namespace rotateAndCropMapperTest {
29
30using namespace android;
31using namespace android::camera3;
32
33using ::testing::ElementsAreArray;
34using ::testing::Each;
35using ::testing::AllOf;
36using ::testing::Ge;
37using ::testing::Le;
38
39#define EXPECT_EQUAL_WITHIN_N(vec, array, N, msg) \
40{ \
41 std::vector<int32_t> vec_diff; \
42 std::transform(vec.begin(), vec.end(), array, \
43 std::back_inserter(vec_diff), std::minus()); \
44 EXPECT_THAT(vec_diff, Each(AllOf(Ge(-N), Le(N)))) << msg; \
45}
46
47int32_t testActiveArray[] = {100, 100, 4000, 3000};
48
49std::vector<uint8_t> basicModes = {
50 ANDROID_SCALER_ROTATE_AND_CROP_NONE,
51 ANDROID_SCALER_ROTATE_AND_CROP_90,
52 ANDROID_SCALER_ROTATE_AND_CROP_AUTO
53};
54
55CameraMetadata setupDeviceInfo(int32_t activeArray[4], std::vector<uint8_t> availableCropModes ) {
56 CameraMetadata deviceInfo;
57
58 deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
59 activeArray, 4);
60
61 deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
62 availableCropModes.data(), availableCropModes.size());
63
64 return deviceInfo;
65}
66
67TEST(RotationMapperTest, Initialization) {
68 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
69 {ANDROID_SCALER_ROTATE_AND_CROP_NONE});
70
71 ASSERT_FALSE(RotateAndCropMapper::isNeeded(&deviceInfo));
72
73 deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
74 basicModes.data(), 3);
75
76 ASSERT_TRUE(RotateAndCropMapper::isNeeded(&deviceInfo));
77}
78
79TEST(RotationMapperTest, IdentityTransform) {
80 status_t res;
81
82 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
83 basicModes);
84
85 RotateAndCropMapper mapper(&deviceInfo);
86
87 CameraMetadata request;
88 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
89 auto full_crop = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3]};
90 auto full_region = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3], 1};
91 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
92 &mode, 1);
93 request.update(ANDROID_SCALER_CROP_REGION,
94 full_crop.data(), full_crop.size());
95 request.update(ANDROID_CONTROL_AE_REGIONS,
96 full_region.data(), full_region.size());
97
98 // Map to HAL
99
100 res = mapper.updateCaptureRequest(&request);
101 ASSERT_TRUE(res == OK);
102
103 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
104 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
105
106 e = request.find(ANDROID_SCALER_CROP_REGION);
107 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
108
109 // Add fields in HAL
110
111 CameraMetadata result(request);
112
113 auto face = std::vector<int32_t> {300,300,500,500};
114 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
115 face.data(), face.size());
116
117 // Map to app
118
119 res = mapper.updateCaptureResult(&result);
120 ASSERT_TRUE(res == OK);
121
122 e = result.find(ANDROID_CONTROL_AE_REGIONS);
123 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
124
125 e = result.find(ANDROID_SCALER_CROP_REGION);
126 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
127
128 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
129 EXPECT_THAT(face, ElementsAreArray(e.data.i32, e.count));
130}
131
132TEST(RotationMapperTest, Transform90) {
133 status_t res;
134
135 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
136 basicModes);
137
138 RotateAndCropMapper mapper(&deviceInfo);
139
140 CameraMetadata request;
141 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_90;
142 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
143 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
144 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
145 &mode, 1);
146 request.update(ANDROID_SCALER_CROP_REGION,
147 full_crop.data(), full_crop.size());
148 request.update(ANDROID_CONTROL_AE_REGIONS,
149 full_region.data(), full_region.size());
150
151 // Map to HAL
152
153 res = mapper.updateCaptureRequest(&request);
154 ASSERT_TRUE(res == OK);
155
156 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
157 float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
158 int32_t rw = full_crop[3] / aspectRatio;
159 int32_t rh = full_crop[3];
160 auto rotated_region = std::vector<int32_t> {
161 full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
162 full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
163 1
164 };
165 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
166 << "Rotated AE region isn't right";
167
168 e = request.find(ANDROID_SCALER_CROP_REGION);
169 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
170 << "Rotated crop region isn't right";
171
172 // Add fields in HAL
173
174 CameraMetadata result(request);
175
176 auto face = std::vector<int32_t> {
177 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
178 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
179 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
180 face.data(), face.size());
181
182 auto landmarks = std::vector<int32_t> {
183 rotated_region[0], rotated_region[1],
184 rotated_region[2], rotated_region[3],
185 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
186 rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
187 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
188 };
189 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
190 landmarks.data(), landmarks.size());
191
192 // Map to app
193
194 res = mapper.updateCaptureResult(&result);
195 ASSERT_TRUE(res == OK);
196
197 // Round-trip results can't be exact since we've gone from a large int range -> small int range
198 // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
199 e = result.find(ANDROID_CONTROL_AE_REGIONS);
200 EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
201
202 e = result.find(ANDROID_SCALER_CROP_REGION);
203 EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
204
205 auto full_face = std::vector<int32_t> {
206 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
207 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
208 };
209 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
210 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
211
212 auto full_landmarks = std::vector<int32_t> {
213 full_crop[0], full_crop[1] + full_crop[3],
214 full_crop[0] + full_crop[2], full_crop[1],
215 full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
216 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
217 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4
218 };
219 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
220 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
221}
222
223TEST(RotationMapperTest, Transform270) {
224 status_t res;
225
226 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
227 basicModes);
228
229 RotateAndCropMapper mapper(&deviceInfo);
230
231 CameraMetadata request;
232 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_270;
233 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
234 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
235 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
236 &mode, 1);
237 request.update(ANDROID_SCALER_CROP_REGION,
238 full_crop.data(), full_crop.size());
239 request.update(ANDROID_CONTROL_AE_REGIONS,
240 full_region.data(), full_region.size());
241
242 // Map to HAL
243
244 res = mapper.updateCaptureRequest(&request);
245 ASSERT_TRUE(res == OK);
246
247 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
248 float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
249 int32_t rw = full_crop[3] / aspectRatio;
250 int32_t rh = full_crop[3];
251 auto rotated_region = std::vector<int32_t> {
252 full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
253 full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
254 1
255 };
256 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
257 << "Rotated AE region isn't right";
258
259 e = request.find(ANDROID_SCALER_CROP_REGION);
260 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
261 << "Rotated crop region isn't right";
262
263 // Add fields in HAL
264
265 CameraMetadata result(request);
266
267 auto face = std::vector<int32_t> {
268 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
269 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
270 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
271 face.data(), face.size());
272
273 auto landmarks = std::vector<int32_t> {
274 rotated_region[0], rotated_region[1],
275 rotated_region[2], rotated_region[3],
276 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
277 rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
278 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
279 };
280 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
281 landmarks.data(), landmarks.size());
282
283 // Map to app
284
285 res = mapper.updateCaptureResult(&result);
286 ASSERT_TRUE(res == OK);
287
288 // Round-trip results can't be exact since we've gone from a large int range -> small int range
289 // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
290
291 e = result.find(ANDROID_CONTROL_AE_REGIONS);
292 EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
293
294 e = result.find(ANDROID_SCALER_CROP_REGION);
295 EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
296
297 auto full_face = std::vector<int32_t> {
298 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
299 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
300 };
301 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
302 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
303
304 auto full_landmarks = std::vector<int32_t> {
305 full_crop[0] + full_crop[2], full_crop[1],
306 full_crop[0], full_crop[1] + full_crop[3],
307 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4,
308 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
309 full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
310 };
311 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
312 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
313}
314
315TEST(RotationMapperTest, Transform180) {
316 status_t res;
317
318 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
319 basicModes);
320
321 RotateAndCropMapper mapper(&deviceInfo);
322
323 CameraMetadata request;
324 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_180;
325 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
326 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
327 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
328 &mode, 1);
329 request.update(ANDROID_SCALER_CROP_REGION,
330 full_crop.data(), full_crop.size());
331 request.update(ANDROID_CONTROL_AE_REGIONS,
332 full_region.data(), full_region.size());
333
334 // Map to HAL
335
336 res = mapper.updateCaptureRequest(&request);
337 ASSERT_TRUE(res == OK);
338
339 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
340 auto rotated_region = full_region;
341 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
342 << "Rotated AE region isn't right";
343
344 e = request.find(ANDROID_SCALER_CROP_REGION);
345 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
346 << "Rotated crop region isn't right";
347
348 // Add fields in HAL
349
350 CameraMetadata result(request);
351
352 float rw = full_region[2] - full_region[0];
353 float rh = full_region[3] - full_region[1];
354 auto face = std::vector<int32_t> {
355 rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
356 rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
357 };
358 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
359 face.data(), face.size());
360
361 auto landmarks = std::vector<int32_t> {
362 rotated_region[0], rotated_region[1],
363 rotated_region[2], rotated_region[3],
364 rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
365 rotated_region[0] + (int)(rw / 2), rotated_region[1] + (int)(rh / 2),
366 rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
367 };
368 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
369 landmarks.data(), landmarks.size());
370
371 // Map to app
372
373 res = mapper.updateCaptureResult(&result);
374 ASSERT_TRUE(res == OK);
375
376 e = result.find(ANDROID_CONTROL_AE_REGIONS);
377 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count))
378 << "Round-tripped AE region isn't right";
379
380 e = result.find(ANDROID_SCALER_CROP_REGION);
381 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
382 << "Round-tripped crop region isn't right";
383
384 auto full_face = std::vector<int32_t> {
385 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
386 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
387 };
388 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
389 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
390
391 auto full_landmarks = std::vector<int32_t> {
392 full_crop[0] + full_crop[2], full_crop[1] + full_crop[3],
393 full_crop[0], full_crop[1],
394 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
395 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
396 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4
397 };
398 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
399 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
400}
401
402
403} // namespace rotateAndCropMapperTest