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