blob: 3c187cd3a78a227a94e0a777db4f81116af7623f [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{ \
Emilian Peev2a245e12020-04-07 16:54:14 -070041 for (size_t i = 0; i < vec.size(); i++) { \
42 EXPECT_THAT(vec[i] - array[i], AllOf(Ge(-N), Le(N))) << msg " failed at index:" << i; \
43 } \
Eino-Ville Talvalaf2e37092020-01-07 15:32:32 -080044}
45
46int32_t testActiveArray[] = {100, 100, 4000, 3000};
47
48std::vector<uint8_t> basicModes = {
49 ANDROID_SCALER_ROTATE_AND_CROP_NONE,
50 ANDROID_SCALER_ROTATE_AND_CROP_90,
51 ANDROID_SCALER_ROTATE_AND_CROP_AUTO
52};
53
54CameraMetadata setupDeviceInfo(int32_t activeArray[4], std::vector<uint8_t> availableCropModes ) {
55 CameraMetadata deviceInfo;
56
57 deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
58 activeArray, 4);
59
60 deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
61 availableCropModes.data(), availableCropModes.size());
62
63 return deviceInfo;
64}
65
66TEST(RotationMapperTest, Initialization) {
67 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
68 {ANDROID_SCALER_ROTATE_AND_CROP_NONE});
69
70 ASSERT_FALSE(RotateAndCropMapper::isNeeded(&deviceInfo));
71
72 deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
73 basicModes.data(), 3);
74
75 ASSERT_TRUE(RotateAndCropMapper::isNeeded(&deviceInfo));
76}
77
78TEST(RotationMapperTest, IdentityTransform) {
79 status_t res;
80
81 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
82 basicModes);
83
84 RotateAndCropMapper mapper(&deviceInfo);
85
86 CameraMetadata request;
87 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
88 auto full_crop = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3]};
89 auto full_region = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3], 1};
90 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
91 &mode, 1);
92 request.update(ANDROID_SCALER_CROP_REGION,
93 full_crop.data(), full_crop.size());
94 request.update(ANDROID_CONTROL_AE_REGIONS,
95 full_region.data(), full_region.size());
96
97 // Map to HAL
98
99 res = mapper.updateCaptureRequest(&request);
100 ASSERT_TRUE(res == OK);
101
102 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
103 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
104
105 e = request.find(ANDROID_SCALER_CROP_REGION);
106 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
107
108 // Add fields in HAL
109
110 CameraMetadata result(request);
111
112 auto face = std::vector<int32_t> {300,300,500,500};
113 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
114 face.data(), face.size());
115
116 // Map to app
117
118 res = mapper.updateCaptureResult(&result);
119 ASSERT_TRUE(res == OK);
120
121 e = result.find(ANDROID_CONTROL_AE_REGIONS);
122 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
123
124 e = result.find(ANDROID_SCALER_CROP_REGION);
125 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
126
127 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
128 EXPECT_THAT(face, ElementsAreArray(e.data.i32, e.count));
129}
130
131TEST(RotationMapperTest, Transform90) {
132 status_t res;
133
134 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
135 basicModes);
136
137 RotateAndCropMapper mapper(&deviceInfo);
138
139 CameraMetadata request;
140 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_90;
141 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
142 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
143 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
144 &mode, 1);
145 request.update(ANDROID_SCALER_CROP_REGION,
146 full_crop.data(), full_crop.size());
147 request.update(ANDROID_CONTROL_AE_REGIONS,
148 full_region.data(), full_region.size());
149
150 // Map to HAL
151
152 res = mapper.updateCaptureRequest(&request);
153 ASSERT_TRUE(res == OK);
154
155 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
156 float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
157 int32_t rw = full_crop[3] / aspectRatio;
158 int32_t rh = full_crop[3];
159 auto rotated_region = std::vector<int32_t> {
160 full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
161 full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
162 1
163 };
164 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
165 << "Rotated AE region isn't right";
166
167 e = request.find(ANDROID_SCALER_CROP_REGION);
168 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
169 << "Rotated crop region isn't right";
170
171 // Add fields in HAL
172
173 CameraMetadata result(request);
174
175 auto face = std::vector<int32_t> {
176 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
177 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
178 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
179 face.data(), face.size());
180
181 auto landmarks = std::vector<int32_t> {
182 rotated_region[0], rotated_region[1],
183 rotated_region[2], rotated_region[3],
184 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
185 rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
186 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
187 };
188 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
189 landmarks.data(), landmarks.size());
190
191 // Map to app
192
193 res = mapper.updateCaptureResult(&result);
194 ASSERT_TRUE(res == OK);
195
196 // Round-trip results can't be exact since we've gone from a large int range -> small int range
197 // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
198 e = result.find(ANDROID_CONTROL_AE_REGIONS);
199 EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
200
201 e = result.find(ANDROID_SCALER_CROP_REGION);
202 EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
203
204 auto full_face = std::vector<int32_t> {
205 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
206 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
207 };
208 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
209 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
210
211 auto full_landmarks = std::vector<int32_t> {
212 full_crop[0], full_crop[1] + full_crop[3],
213 full_crop[0] + full_crop[2], full_crop[1],
214 full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
215 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
216 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4
217 };
218 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
219 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
220}
221
222TEST(RotationMapperTest, Transform270) {
223 status_t res;
224
225 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
226 basicModes);
227
228 RotateAndCropMapper mapper(&deviceInfo);
229
230 CameraMetadata request;
231 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_270;
232 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
233 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
234 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
235 &mode, 1);
236 request.update(ANDROID_SCALER_CROP_REGION,
237 full_crop.data(), full_crop.size());
238 request.update(ANDROID_CONTROL_AE_REGIONS,
239 full_region.data(), full_region.size());
240
241 // Map to HAL
242
243 res = mapper.updateCaptureRequest(&request);
244 ASSERT_TRUE(res == OK);
245
246 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
247 float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
248 int32_t rw = full_crop[3] / aspectRatio;
249 int32_t rh = full_crop[3];
250 auto rotated_region = std::vector<int32_t> {
251 full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
252 full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
253 1
254 };
255 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
256 << "Rotated AE region isn't right";
257
258 e = request.find(ANDROID_SCALER_CROP_REGION);
259 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
260 << "Rotated crop region isn't right";
261
262 // Add fields in HAL
263
264 CameraMetadata result(request);
265
266 auto face = std::vector<int32_t> {
267 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
268 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
269 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
270 face.data(), face.size());
271
272 auto landmarks = std::vector<int32_t> {
273 rotated_region[0], rotated_region[1],
274 rotated_region[2], rotated_region[3],
275 rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
276 rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
277 rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
278 };
279 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
280 landmarks.data(), landmarks.size());
281
282 // Map to app
283
284 res = mapper.updateCaptureResult(&result);
285 ASSERT_TRUE(res == OK);
286
287 // Round-trip results can't be exact since we've gone from a large int range -> small int range
288 // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
289
290 e = result.find(ANDROID_CONTROL_AE_REGIONS);
291 EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
292
293 e = result.find(ANDROID_SCALER_CROP_REGION);
294 EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
295
296 auto full_face = std::vector<int32_t> {
297 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
298 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
299 };
300 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
301 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
302
303 auto full_landmarks = std::vector<int32_t> {
304 full_crop[0] + full_crop[2], full_crop[1],
305 full_crop[0], full_crop[1] + full_crop[3],
306 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4,
307 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
308 full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
309 };
310 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
311 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
312}
313
314TEST(RotationMapperTest, Transform180) {
315 status_t res;
316
317 CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
318 basicModes);
319
320 RotateAndCropMapper mapper(&deviceInfo);
321
322 CameraMetadata request;
323 uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_180;
324 auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
325 auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
326 request.update(ANDROID_SCALER_ROTATE_AND_CROP,
327 &mode, 1);
328 request.update(ANDROID_SCALER_CROP_REGION,
329 full_crop.data(), full_crop.size());
330 request.update(ANDROID_CONTROL_AE_REGIONS,
331 full_region.data(), full_region.size());
332
333 // Map to HAL
334
335 res = mapper.updateCaptureRequest(&request);
336 ASSERT_TRUE(res == OK);
337
338 auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
339 auto rotated_region = full_region;
340 EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
341 << "Rotated AE region isn't right";
342
343 e = request.find(ANDROID_SCALER_CROP_REGION);
344 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
345 << "Rotated crop region isn't right";
346
347 // Add fields in HAL
348
349 CameraMetadata result(request);
350
351 float rw = full_region[2] - full_region[0];
352 float rh = full_region[3] - full_region[1];
353 auto face = std::vector<int32_t> {
354 rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
355 rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
356 };
357 result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
358 face.data(), face.size());
359
360 auto landmarks = std::vector<int32_t> {
361 rotated_region[0], rotated_region[1],
362 rotated_region[2], rotated_region[3],
363 rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
364 rotated_region[0] + (int)(rw / 2), rotated_region[1] + (int)(rh / 2),
365 rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
366 };
367 result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
368 landmarks.data(), landmarks.size());
369
370 // Map to app
371
372 res = mapper.updateCaptureResult(&result);
373 ASSERT_TRUE(res == OK);
374
375 e = result.find(ANDROID_CONTROL_AE_REGIONS);
376 EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count))
377 << "Round-tripped AE region isn't right";
378
379 e = result.find(ANDROID_SCALER_CROP_REGION);
380 EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
381 << "Round-tripped crop region isn't right";
382
383 auto full_face = std::vector<int32_t> {
384 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
385 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
386 };
387 e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
388 EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
389
390 auto full_landmarks = std::vector<int32_t> {
391 full_crop[0] + full_crop[2], full_crop[1] + full_crop[3],
392 full_crop[0], full_crop[1],
393 full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
394 full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
395 full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4
396 };
397 e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
398 EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
399}
400
401
402} // namespace rotateAndCropMapperTest