• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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_TAG "Camera3-DistMapper"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20 
21 #include <algorithm>
22 #include <cmath>
23 
24 #include "device3/DistortionMapper.h"
25 #include "utils/SessionConfigurationUtilsHost.h"
26 
27 namespace android {
28 
29 namespace camera3 {
30 
DistortionMapper()31 DistortionMapper::DistortionMapper() {
32     initRemappedKeys();
33 }
34 
initRemappedKeys()35 void DistortionMapper::initRemappedKeys() {
36     mRemappedKeys.insert(
37             kMeteringRegionsToCorrect.begin(),
38             kMeteringRegionsToCorrect.end());
39     mRemappedKeys.insert(
40             kRectsToCorrect.begin(),
41             kRectsToCorrect.end());
42     mRemappedKeys.insert(
43             kResultPointsToCorrectNoClamp.begin(),
44             kResultPointsToCorrectNoClamp.end());
45     mRemappedKeys.insert(ANDROID_DISTORTION_CORRECTION_MODE);
46     if (flags::concert_mode()) {
47         mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
48     }
49 }
50 
isDistortionSupported(const CameraMetadata & deviceInfo)51 bool DistortionMapper::isDistortionSupported(const CameraMetadata &deviceInfo) {
52     bool isDistortionCorrectionSupported = false;
53     camera_metadata_ro_entry_t distortionCorrectionModes =
54             deviceInfo.find(ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES);
55     for (size_t i = 0; i < distortionCorrectionModes.count; i++) {
56         if (distortionCorrectionModes.data.u8[i] !=
57                 ANDROID_DISTORTION_CORRECTION_MODE_OFF) {
58             isDistortionCorrectionSupported = true;
59             break;
60         }
61     }
62     return isDistortionCorrectionSupported;
63 }
64 
setupStaticInfo(const CameraMetadata & deviceInfo)65 status_t DistortionMapper::setupStaticInfo(const CameraMetadata &deviceInfo) {
66     std::lock_guard<std::mutex> lock(mMutex);
67     status_t res = setupStaticInfoLocked(deviceInfo, /*maxResolution*/false);
68     if (res != OK) {
69         return res;
70     }
71 
72     bool mMaxResolution = SessionConfigurationUtils::supportsUltraHighResolutionCapture(deviceInfo);
73     if (mMaxResolution) {
74         res = setupStaticInfoLocked(deviceInfo, /*maxResolution*/true);
75     }
76     return res;
77 }
78 
setupStaticInfoLocked(const CameraMetadata & deviceInfo,bool maxResolution)79 status_t DistortionMapper::setupStaticInfoLocked(const CameraMetadata &deviceInfo,
80         bool maxResolution) {
81     DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
82             &mDistortionMapperInfo;
83 
84     camera_metadata_ro_entry_t array;
85 
86     array = deviceInfo.find(
87         SessionConfigurationUtils::getAppropriateModeTag(
88                 ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, maxResolution));
89     if (array.count != 4) return BAD_VALUE;
90 
91     float arrayX = static_cast<float>(array.data.i32[0]);
92     float arrayY = static_cast<float>(array.data.i32[1]);
93     mapperInfo->mArrayWidth = static_cast<float>(array.data.i32[2]);
94     mapperInfo->mArrayHeight = static_cast<float>(array.data.i32[3]);
95 
96     array = deviceInfo.find(
97             SessionConfigurationUtils::getAppropriateModeTag(
98                     ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, maxResolution));
99     if (array.count != 4) return BAD_VALUE;
100 
101     float activeX = static_cast<float>(array.data.i32[0]);
102     float activeY = static_cast<float>(array.data.i32[1]);
103     mapperInfo->mActiveWidth = static_cast<float>(array.data.i32[2]);
104     mapperInfo->mActiveHeight = static_cast<float>(array.data.i32[3]);
105 
106     mapperInfo->mArrayDiffX = activeX - arrayX;
107     mapperInfo->mArrayDiffY = activeY - arrayY;
108 
109     return updateCalibration(deviceInfo, /*isStatic*/ true, maxResolution);
110 }
111 
doesSettingsHaveMaxResolution(const CameraMetadata * settings)112 static bool doesSettingsHaveMaxResolution(const CameraMetadata *settings) {
113     if (settings == nullptr) {
114         return false;
115     }
116     // First we get the sensorPixelMode from the settings metadata.
117     camera_metadata_ro_entry sensorPixelModeEntry = settings->find(ANDROID_SENSOR_PIXEL_MODE);
118     if (sensorPixelModeEntry.count != 0) {
119         return (sensorPixelModeEntry.data.u8[0] == ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
120     }
121     return false;
122 }
123 
calibrationValid() const124 bool DistortionMapper::calibrationValid() const {
125     std::lock_guard<std::mutex> lock(mMutex);
126     bool isValid =  mDistortionMapperInfo.mValidMapping;
127     if (mMaxResolution) {
128         isValid = isValid && mDistortionMapperInfoMaximumResolution.mValidMapping;
129     }
130     return isValid;
131 }
132 
correctCaptureRequest(CameraMetadata * request)133 status_t DistortionMapper::correctCaptureRequest(CameraMetadata *request) {
134     std::lock_guard<std::mutex> lock(mMutex);
135     status_t res;
136 
137     bool maxResolution = doesSettingsHaveMaxResolution(request);
138     DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
139             &mDistortionMapperInfo;
140 
141     if (!mapperInfo->mValidMapping) return OK;
142 
143     camera_metadata_entry_t e;
144     e = request->find(ANDROID_DISTORTION_CORRECTION_MODE);
145     if (e.count != 0 && e.data.u8[0] != ANDROID_DISTORTION_CORRECTION_MODE_OFF) {
146         for (auto region : kMeteringRegionsToCorrect) {
147             e = request->find(region);
148             for (size_t j = 0; j < e.count; j += 5) {
149                 int32_t weight = e.data.i32[j + 4];
150                 if (weight == 0) {
151                     continue;
152                 }
153                 res = mapCorrectedToRaw(e.data.i32 + j, 2, mapperInfo, /*clamp*/true);
154                 if (res != OK) return res;
155             }
156         }
157         for (auto rect : kRectsToCorrect) {
158             e = request->find(rect);
159             res = mapCorrectedRectToRaw(e.data.i32, e.count / 4, mapperInfo, /*clamp*/true);
160             if (res != OK) return res;
161         }
162     }
163     return OK;
164 }
165 
correctCaptureResult(CameraMetadata * result)166 status_t DistortionMapper::correctCaptureResult(CameraMetadata *result) {
167     std::lock_guard<std::mutex> lock(mMutex);
168 
169     bool maxResolution = doesSettingsHaveMaxResolution(result);
170     DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
171             &mDistortionMapperInfo;
172     status_t res;
173 
174     if (!mapperInfo->mValidMapping) return OK;
175 
176     res = updateCalibration(*result, /*isStatic*/ false, maxResolution);
177     if (res != OK) {
178         ALOGE("Failure to update lens calibration information");
179         return INVALID_OPERATION;
180     }
181 
182     camera_metadata_entry_t e;
183     e = result->find(ANDROID_DISTORTION_CORRECTION_MODE);
184     if (e.count != 0 && e.data.u8[0] != ANDROID_DISTORTION_CORRECTION_MODE_OFF) {
185         for (auto region : kMeteringRegionsToCorrect) {
186             e = result->find(region);
187             for (size_t j = 0; j < e.count; j += 5) {
188                 int32_t weight = e.data.i32[j + 4];
189                 if (weight == 0) {
190                     continue;
191                 }
192                 res = mapRawToCorrected(e.data.i32 + j, 2, mapperInfo, /*clamp*/true);
193                 if (res != OK) return res;
194             }
195         }
196         for (auto rect : kRectsToCorrect) {
197             e = result->find(rect);
198             res = mapRawRectToCorrected(e.data.i32, e.count / 4, mapperInfo, /*clamp*/true);
199             if (res != OK) return res;
200         }
201         for (auto pts : kResultPointsToCorrectNoClamp) {
202             e = result->find(pts);
203             res = mapRawToCorrected(e.data.i32, e.count / 2, mapperInfo, /*clamp*/false);
204             if (res != OK) return res;
205         }
206     }
207 
208     return OK;
209 }
210 
211 // Utility methods; not guarded by mutex
212 
updateCalibration(const CameraMetadata & result,bool isStatic,bool maxResolution)213 status_t DistortionMapper::updateCalibration(const CameraMetadata &result, bool isStatic,
214         bool maxResolution) {
215     camera_metadata_ro_entry_t calib, distortion;
216     DistortionMapperInfo *mapperInfo =
217             maxResolution ? &mDistortionMapperInfoMaximumResolution : &mDistortionMapperInfo;
218     // We only need maximum resolution version of LENS_INTRINSIC_CALIBRATION and
219     // LENS_DISTORTION since CaptureResults would still use the same key
220     // regardless of sensor pixel mode.
221     int calibrationKey =
222         SessionConfigurationUtils::getAppropriateModeTag(ANDROID_LENS_INTRINSIC_CALIBRATION,
223                 maxResolution && isStatic);
224     int distortionKey =
225         SessionConfigurationUtils::getAppropriateModeTag(ANDROID_LENS_DISTORTION,
226                 maxResolution && isStatic);
227 
228     calib = result.find(calibrationKey);
229     distortion = result.find(distortionKey);
230 
231     if (calib.count != 5) return BAD_VALUE;
232     if (distortion.count != 5) return BAD_VALUE;
233 
234     // Skip redoing work if no change to calibration fields
235     if (mapperInfo->mValidMapping &&
236             mapperInfo->mFx == calib.data.f[0] &&
237             mapperInfo->mFy == calib.data.f[1] &&
238             mapperInfo->mCx == calib.data.f[2] &&
239             mapperInfo->mCy == calib.data.f[3] &&
240             mapperInfo->mS == calib.data.f[4]) {
241         bool noChange = true;
242         for (size_t i = 0; i < distortion.count; i++) {
243             if (mapperInfo->mK[i] != distortion.data.f[i]) {
244                 noChange = false;
245                 break;
246             }
247         }
248         if (noChange) return OK;
249     }
250 
251     mapperInfo->mFx = calib.data.f[0];
252     mapperInfo->mFy = calib.data.f[1];
253     mapperInfo->mCx = calib.data.f[2];
254     mapperInfo->mCy = calib.data.f[3];
255     mapperInfo->mS = calib.data.f[4];
256 
257     mapperInfo->mInvFx = 1 / mapperInfo->mFx;
258     mapperInfo->mInvFy = 1 / mapperInfo->mFy;
259 
260     for (size_t i = 0; i < distortion.count; i++) {
261         mapperInfo->mK[i] = distortion.data.f[i];
262     }
263 
264     mapperInfo->mValidMapping = true;
265     // Need to recalculate grid
266     mapperInfo->mValidGrids = false;
267 
268     return OK;
269 }
270 
mapRawToCorrected(int32_t * coordPairs,int coordCount,DistortionMapperInfo * mapperInfo,bool clamp,bool simple)271 status_t DistortionMapper::mapRawToCorrected(int32_t *coordPairs, int coordCount,
272         DistortionMapperInfo *mapperInfo, bool clamp, bool simple) {
273     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
274 
275     if (simple) return mapRawToCorrectedSimple(coordPairs, coordCount, mapperInfo, clamp);
276 
277     if (!mapperInfo->mValidGrids) {
278         status_t res = buildGrids(mapperInfo);
279         if (res != OK) return res;
280     }
281 
282     for (int i = 0; i < coordCount * 2; i += 2) {
283         const GridQuad *quad = findEnclosingQuad(coordPairs + i, mapperInfo->mDistortedGrid);
284         if (quad == nullptr) {
285             ALOGE("Raw to corrected mapping failure: No quad found for (%d, %d)",
286                     *(coordPairs + i), *(coordPairs + i + 1));
287             return INVALID_OPERATION;
288         }
289         ALOGV("src xy: %d, %d, enclosing quad: (%f, %f), (%f, %f), (%f, %f), (%f, %f)",
290                 coordPairs[i], coordPairs[i+1],
291                 quad->coords[0], quad->coords[1],
292                 quad->coords[2], quad->coords[3],
293                 quad->coords[4], quad->coords[5],
294                 quad->coords[6], quad->coords[7]);
295 
296         const GridQuad *corrQuad = quad->src;
297         if (corrQuad == nullptr) {
298             ALOGE("Raw to corrected mapping failure: No src quad found");
299             return INVALID_OPERATION;
300         }
301         ALOGV("              corr quad: (%f, %f), (%f, %f), (%f, %f), (%f, %f)",
302                 corrQuad->coords[0], corrQuad->coords[1],
303                 corrQuad->coords[2], corrQuad->coords[3],
304                 corrQuad->coords[4], corrQuad->coords[5],
305                 corrQuad->coords[6], corrQuad->coords[7]);
306 
307         float u = calculateUorV(coordPairs + i, *quad, /*calculateU*/ true);
308         float v = calculateUorV(coordPairs + i, *quad, /*calculateU*/ false);
309 
310         ALOGV("uv: %f, %f", u, v);
311 
312         // Interpolate along top edge of corrected quad (which are axis-aligned) for x
313         float corrX = corrQuad->coords[0] + u * (corrQuad->coords[2] - corrQuad->coords[0]);
314         // Interpolate along left edge of corrected quad (which are axis-aligned) for y
315         float corrY = corrQuad->coords[1] + v * (corrQuad->coords[7] - corrQuad->coords[1]);
316 
317         // Clamp to within active array
318         if (clamp) {
319             corrX = std::min(mapperInfo->mActiveWidth - 1, std::max(0.f, corrX));
320             corrY = std::min(mapperInfo->mActiveHeight - 1, std::max(0.f, corrY));
321         }
322 
323         coordPairs[i] = static_cast<int32_t>(std::round(corrX));
324         coordPairs[i + 1] = static_cast<int32_t>(std::round(corrY));
325     }
326 
327     return OK;
328 }
329 
mapRawToCorrectedSimple(int32_t * coordPairs,int coordCount,const DistortionMapperInfo * mapperInfo,bool clamp) const330 status_t DistortionMapper::mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount,
331        const DistortionMapperInfo *mapperInfo, bool clamp) const {
332     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
333 
334     float scaleX = mapperInfo->mActiveWidth / mapperInfo->mArrayWidth;
335     float scaleY = mapperInfo->mActiveHeight / mapperInfo->mArrayHeight;
336     for (int i = 0; i < coordCount * 2; i += 2) {
337         float x = coordPairs[i];
338         float y = coordPairs[i + 1];
339         float corrX = x * scaleX;
340         float corrY = y * scaleY;
341         if (clamp) {
342             corrX = std::min(mapperInfo->mActiveWidth - 1, std::max(0.f, corrX));
343             corrY = std::min(mapperInfo->mActiveHeight - 1, std::max(0.f, corrY));
344         }
345         coordPairs[i] = static_cast<int32_t>(std::round(corrX));
346         coordPairs[i + 1] = static_cast<int32_t>(std::round(corrY));
347     }
348 
349     return OK;
350 }
351 
mapRawRectToCorrected(int32_t * rects,int rectCount,DistortionMapperInfo * mapperInfo,bool clamp,bool simple)352 status_t DistortionMapper::mapRawRectToCorrected(int32_t *rects, int rectCount,
353        DistortionMapperInfo *mapperInfo, bool clamp, bool simple) {
354     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
355     for (int i = 0; i < rectCount * 4; i += 4) {
356         // Map from (l, t, width, height) to (l, t, r, b)
357         int32_t coords[4] = {
358             rects[i],
359             rects[i + 1],
360             rects[i] + rects[i + 2] - 1,
361             rects[i + 1] + rects[i + 3] - 1
362         };
363 
364         mapRawToCorrected(coords, 2, mapperInfo, clamp, simple);
365 
366         // Map back to (l, t, width, height)
367         rects[i] = coords[0];
368         rects[i + 1] = coords[1];
369         rects[i + 2] = coords[2] - coords[0] + 1;
370         rects[i + 3] = coords[3] - coords[1] + 1;
371     }
372 
373     return OK;
374 }
375 
mapCorrectedToRaw(int32_t * coordPairs,int coordCount,const DistortionMapperInfo * mapperInfo,bool clamp,bool simple) const376 status_t DistortionMapper::mapCorrectedToRaw(int32_t *coordPairs, int coordCount,
377        const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
378     return mapCorrectedToRawImpl(coordPairs, coordCount, mapperInfo, clamp, simple);
379 }
380 
381 template<typename T>
mapCorrectedToRawImpl(T * coordPairs,int coordCount,const DistortionMapperInfo * mapperInfo,bool clamp,bool simple) const382 status_t DistortionMapper::mapCorrectedToRawImpl(T *coordPairs, int coordCount,
383        const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
384     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
385 
386     if (simple) return mapCorrectedToRawImplSimple(coordPairs, coordCount, mapperInfo, clamp);
387 
388     float activeCx = mapperInfo->mCx - mapperInfo->mArrayDiffX;
389     float activeCy = mapperInfo->mCy - mapperInfo->mArrayDiffY;
390     for (int i = 0; i < coordCount * 2; i += 2) {
391         // Move to normalized space from active array space
392         float ywi = (coordPairs[i + 1] - activeCy) * mapperInfo->mInvFy;
393         float xwi = (coordPairs[i] - activeCx - mapperInfo->mS * ywi) * mapperInfo->mInvFx;
394         // Apply distortion model to calculate raw image coordinates
395         const std::array<float, 5> &kK = mapperInfo->mK;
396         float rSq = xwi * xwi + ywi * ywi;
397         float Fr = 1.f + (kK[0] * rSq) + (kK[1] * rSq * rSq) + (kK[2] * rSq * rSq * rSq);
398         float xc = xwi * Fr + (kK[3] * 2 * xwi * ywi) + kK[4] * (rSq + 2 * xwi * xwi);
399         float yc = ywi * Fr + (kK[4] * 2 * xwi * ywi) + kK[3] * (rSq + 2 * ywi * ywi);
400         // Move back to image space
401         float xr = mapperInfo->mFx * xc + mapperInfo->mS * yc + mapperInfo->mCx;
402         float yr = mapperInfo->mFy * yc + mapperInfo->mCy;
403         // Clamp to within pre-correction active array
404         if (clamp) {
405             xr = std::min(mapperInfo->mArrayWidth - 1, std::max(0.f, xr));
406             yr = std::min(mapperInfo->mArrayHeight - 1, std::max(0.f, yr));
407         }
408 
409         coordPairs[i] = static_cast<T>(std::round(xr));
410         coordPairs[i + 1] = static_cast<T>(std::round(yr));
411     }
412     return OK;
413 }
414 
415 template<typename T>
mapCorrectedToRawImplSimple(T * coordPairs,int coordCount,const DistortionMapperInfo * mapperInfo,bool clamp) const416 status_t DistortionMapper::mapCorrectedToRawImplSimple(T *coordPairs, int coordCount,
417        const DistortionMapperInfo *mapperInfo, bool clamp) const {
418     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
419 
420     float scaleX = mapperInfo->mArrayWidth / mapperInfo->mActiveWidth;
421     float scaleY = mapperInfo->mArrayHeight / mapperInfo->mActiveHeight;
422     for (int i = 0; i < coordCount * 2; i += 2) {
423         float x = coordPairs[i];
424         float y = coordPairs[i + 1];
425         float rawX = x * scaleX;
426         float rawY = y * scaleY;
427         if (clamp) {
428             rawX = std::min(mapperInfo->mArrayWidth - 1, std::max(0.f, rawX));
429             rawY = std::min(mapperInfo->mArrayHeight - 1, std::max(0.f, rawY));
430         }
431         coordPairs[i] = static_cast<T>(std::round(rawX));
432         coordPairs[i + 1] = static_cast<T>(std::round(rawY));
433     }
434 
435     return OK;
436 }
437 
mapCorrectedRectToRaw(int32_t * rects,int rectCount,const DistortionMapperInfo * mapperInfo,bool clamp,bool simple) const438 status_t DistortionMapper::mapCorrectedRectToRaw(int32_t *rects, int rectCount,
439        const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
440     if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
441 
442     for (int i = 0; i < rectCount * 4; i += 4) {
443         // Map from (l, t, width, height) to (l, t, r, b)
444         int32_t coords[4] = {
445             rects[i],
446             rects[i + 1],
447             rects[i] + rects[i + 2] - 1,
448             rects[i + 1] + rects[i + 3] - 1
449         };
450 
451         mapCorrectedToRaw(coords, 2, mapperInfo, clamp, simple);
452 
453         // Map back to (l, t, width, height)
454         rects[i] = coords[0];
455         rects[i + 1] = coords[1];
456         rects[i + 2] = coords[2] - coords[0] + 1;
457         rects[i + 3] = coords[3] - coords[1] + 1;
458     }
459 
460     return OK;
461 }
462 
buildGrids(DistortionMapperInfo * mapperInfo)463 status_t DistortionMapper::buildGrids(DistortionMapperInfo *mapperInfo) {
464     if (mapperInfo->mCorrectedGrid.size() != kGridSize * kGridSize) {
465         mapperInfo->mCorrectedGrid.resize(kGridSize * kGridSize);
466         mapperInfo->mDistortedGrid.resize(kGridSize * kGridSize);
467     }
468 
469     float gridMargin = mapperInfo->mArrayWidth * kGridMargin;
470     float gridSpacingX = (mapperInfo->mArrayWidth + 2 * gridMargin) / kGridSize;
471     float gridSpacingY = (mapperInfo->mArrayHeight + 2 * gridMargin) / kGridSize;
472 
473     size_t index = 0;
474     float x = -gridMargin;
475     for (size_t i = 0; i < kGridSize; i++, x += gridSpacingX) {
476         float y = -gridMargin;
477         for (size_t j = 0; j < kGridSize; j++, y += gridSpacingY, index++) {
478             mapperInfo->mCorrectedGrid[index].src = nullptr;
479             mapperInfo->mCorrectedGrid[index].coords = {
480                 x, y,
481                 x + gridSpacingX, y,
482                 x + gridSpacingX, y + gridSpacingY,
483                 x, y + gridSpacingY
484             };
485             mapperInfo->mDistortedGrid[index].src = &(mapperInfo->mCorrectedGrid[index]);
486             mapperInfo->mDistortedGrid[index].coords = mapperInfo->mCorrectedGrid[index].coords;
487             status_t res = mapCorrectedToRawImpl(mapperInfo->mDistortedGrid[index].coords.data(), 4,
488                     mapperInfo, /*clamp*/false, /*simple*/false);
489             if (res != OK) return res;
490         }
491     }
492 
493     mapperInfo->mValidGrids = true;
494     return OK;
495 }
496 
findEnclosingQuad(const int32_t pt[2],const std::vector<GridQuad> & grid)497 const DistortionMapper::GridQuad* DistortionMapper::findEnclosingQuad(
498         const int32_t pt[2], const std::vector<GridQuad>& grid) {
499     const float x = pt[0];
500     const float y = pt[1];
501 
502     for (const GridQuad& quad : grid) {
503         const float &x1 = quad.coords[0];
504         const float &y1 = quad.coords[1];
505         const float &x2 = quad.coords[2];
506         const float &y2 = quad.coords[3];
507         const float &x3 = quad.coords[4];
508         const float &y3 = quad.coords[5];
509         const float &x4 = quad.coords[6];
510         const float &y4 = quad.coords[7];
511 
512         // Point-in-quad test:
513 
514         // Quad has corners P1-P4; if P is within the quad, then it is on the same side of all the
515         // edges (or on top of one of the edges or corners), traversed in a consistent direction.
516         // This means that the cross product of edge En = Pn->P(n+1 mod 4) and line Ep = Pn->P must
517         // have the same sign (or be zero) for all edges.
518         // For clockwise traversal, the sign should be negative or zero for Ep x En, indicating that
519         // En is to the left of Ep, or overlapping.
520         float s1 = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1);
521         if (s1 > 0) continue;
522         float s2 = (x - x2) * (y3 - y2) - (y - y2) * (x3 - x2);
523         if (s2 > 0) continue;
524         float s3 = (x - x3) * (y4 - y3) - (y - y3) * (x4 - x3);
525         if (s3 > 0) continue;
526         float s4 = (x - x4) * (y1 - y4) - (y - y4) * (x1 - x4);
527         if (s4 > 0) continue;
528 
529         return &quad;
530     }
531     return nullptr;
532 }
533 
calculateUorV(const int32_t pt[2],const GridQuad & quad,bool calculateU)534 float DistortionMapper::calculateUorV(const int32_t pt[2], const GridQuad& quad, bool calculateU) {
535     const float x = pt[0];
536     const float y = pt[1];
537     const float &x1 = quad.coords[0];
538     const float &y1 = quad.coords[1];
539     const float &x2 = calculateU ? quad.coords[2] : quad.coords[6];
540     const float &y2 = calculateU ? quad.coords[3] : quad.coords[7];
541     const float &x3 = quad.coords[4];
542     const float &y3 = quad.coords[5];
543     const float &x4 = calculateU ? quad.coords[6] : quad.coords[2];
544     const float &y4 = calculateU ? quad.coords[7] : quad.coords[3];
545 
546     float a = (x1 - x2) * (y1 - y2 + y3 - y4) - (y1 - y2) * (x1 - x2 + x3 - x4);
547     float b = (x - x1) * (y1 - y2 + y3 - y4) + (x1 - x2) * (y4 - y1) -
548               (y - y1) * (x1 - x2 + x3 - x4) - (y1 - y2) * (x4 - x1);
549     float c = (x - x1) * (y4 - y1) - (y - y1) * (x4 - x1);
550 
551     if (a == 0) {
552         // One solution may happen if edges are parallel
553         float u0 = -c / b;
554         ALOGV("u0: %.9g, b: %f, c: %f", u0, b, c);
555         return u0;
556     }
557 
558     float det = b * b - 4 * a * c;
559     if (det < 0) {
560         // Validation check - should not happen if pt is within the quad
561         ALOGE("Bad determinant! a: %f, b: %f, c: %f, det: %f", a,b,c,det);
562         return -1;
563     }
564 
565     // Select more numerically stable solution
566     float sqdet = b > 0 ? -std::sqrt(det) : std::sqrt(det);
567 
568     float u1 = (-b + sqdet) / (2 * a);
569     ALOGV("u1: %.9g", u1);
570     if (0 - kFloatFuzz < u1 && u1 < 1 + kFloatFuzz) return u1;
571 
572     float u2 = c / (a * u1);
573     ALOGV("u2: %.9g", u2);
574     if (0 - kFloatFuzz < u2 && u2 < 1 + kFloatFuzz) return u2;
575 
576     // Last resort, return the smaller-magnitude solution
577     return fabs(u1) < fabs(u2) ? u1 : u2;
578 }
579 
580 } // namespace camera3
581 
582 } // namespace android
583