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 #ifndef ANDROID_SERVERS_DISTORTIONMAPPER_H
18 #define ANDROID_SERVERS_DISTORTIONMAPPER_H
19 
20 #include <utils/Errors.h>
21 #include <array>
22 #include <mutex>
23 
24 #include "camera/CameraMetadata.h"
25 #include "device3/CoordinateMapper.h"
26 
27 namespace android {
28 
29 namespace camera3 {
30 
31 /**
32  * Utilities to transform between raw (distorted) and warped (corrected) coordinate systems
33  * for cameras that support geometric distortion
34  */
35 class DistortionMapper : private CoordinateMapper {
36   public:
37     DistortionMapper();
38 
DistortionMapper(const DistortionMapper & other)39     DistortionMapper(const DistortionMapper& other) :
40             mValidMapping(other.mValidMapping), mValidGrids(other.mValidGrids),
41             mFx(other.mFx), mFy(other.mFy), mCx(other.mCx), mCy(other.mCy), mS(other.mS),
42             mInvFx(other.mInvFx), mInvFy(other.mInvFy), mK(other.mK),
43             mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
44             mActiveWidth(other.mActiveWidth), mActiveHeight(other.mActiveHeight),
45             mArrayDiffX(other.mArrayDiffX), mArrayDiffY(other.mArrayDiffY),
46             mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {}
47 
48     /**
49      * Check whether distortion correction is supported by the camera HAL
50      */
51     static bool isDistortionSupported(const CameraMetadata &deviceInfo);
52 
53     /**
54      * Update static lens calibration info from camera characteristics
55      */
56     status_t setupStaticInfo(const CameraMetadata &deviceInfo);
57 
58     /**
59      * Return whether distortion correction can be applied currently
60      */
61     bool calibrationValid() const;
62 
63     /**
64      * Correct capture request if distortion correction is enabled
65      */
66     status_t correctCaptureRequest(CameraMetadata *request);
67 
68     /**
69      * Correct capture result if distortion correction is enabled
70      */
71     status_t correctCaptureResult(CameraMetadata *request);
72 
73 
74   public: // Visible for testing. Not guarded by mutex; do not use concurrently
75     /**
76      * Update lens calibration from capture results or equivalent
77      */
78     status_t updateCalibration(const CameraMetadata &result);
79 
80     /**
81      * Transform from distorted (original) to corrected (warped) coordinates.
82      * Coordinates are transformed in-place
83      *
84      *   coordPairs: A pointer to an array of consecutive (x,y) points
85      *   coordCount: Number of (x,y) pairs to transform
86      *   clamp: Whether to clamp the result to the bounds of the active array
87      *   simple: Whether to do complex correction or just a simple linear map
88      */
89     status_t mapRawToCorrected(int32_t *coordPairs, int coordCount, bool clamp,
90             bool simple = true);
91 
92     /**
93      * Transform from distorted (original) to corrected (warped) coordinates.
94      * Coordinates are transformed in-place
95      *
96      *   rects: A pointer to an array of consecutive (x,y, w, h) rectangles
97      *   rectCount: Number of rectangles to transform
98      *   clamp: Whether to clamp the result to the bounds of the active array
99      *   simple: Whether to do complex correction or just a simple linear map
100      */
101     status_t mapRawRectToCorrected(int32_t *rects, int rectCount, bool clamp,
102             bool simple = true);
103 
104     /**
105      * Transform from corrected (warped) to distorted (original) coordinates.
106      * Coordinates are transformed in-place
107      *
108      *   coordPairs: A pointer to an array of consecutive (x,y) points
109      *   coordCount: Number of (x,y) pairs to transform
110      *   clamp: Whether to clamp the result to the bounds of the precorrection active array
111      *   simple: Whether to do complex correction or just a simple linear map
112      */
113     status_t mapCorrectedToRaw(int32_t* coordPairs, int coordCount, bool clamp,
114             bool simple = true) const;
115 
116     /**
117      * Transform from corrected (warped) to distorted (original) coordinates.
118      * Coordinates are transformed in-place
119      *
120      *   rects: A pointer to an array of consecutive (x,y, w, h) rectangles
121      *   rectCount: Number of rectangles to transform
122      *   clamp: Whether to clamp the result to the bounds of the precorrection active array
123      *   simple: Whether to do complex correction or just a simple linear map
124      */
125     status_t mapCorrectedRectToRaw(int32_t *rects, int rectCount, bool clamp,
126             bool simple = true) const;
127 
128     struct GridQuad {
129         // Source grid quad, or null
130         const GridQuad *src;
131         // x,y coordinates of corners, in
132         // clockwise order
133         std::array<float, 8> coords;
134     };
135 
136     // Find which grid quad encloses the point; returns null if none do
137     static const GridQuad* findEnclosingQuad(
138             const int32_t pt[2], const std::vector<GridQuad>& grid);
139 
140     // Calculate 'horizontal' interpolation coordinate for the point and the quad
141     // Assumes the point P is within the quad Q.
142     // Given quad with points P1-P4, and edges E12-E41, and considering the edge segments as
143     // functions of U: E12(u), where E12(0) = P1 and E12(1) = P2, then we want to find a u
144     // such that the edge E12(u) -> E43(u) contains point P.
145     // This can be determined by checking if the cross product of vector [E12(u)-E43(u)] and
146     // vector [E12(u)-P] is zero. Solving the equation
147     // [E12(u)-E43(u)] x [E12(u)-P] = 0 gives a quadratic equation in u; the solution in the range
148     // 0 to 1 is the one chosen.
149     // If calculateU is true, then an interpolation coordinate for edges E12 and E43 is found;
150     // if it is false, then an interpolation coordinate for edges E14 and E23 is found.
151     static float calculateUorV(const int32_t pt[2], const GridQuad& quad, bool calculateU);
152 
153   private:
154     mutable std::mutex mMutex;
155 
156     // Number of quads in each dimension of the mapping grids
157     constexpr static size_t kGridSize = 15;
158     // Margin to expand the grid by to ensure it doesn't clip the domain
159     constexpr static float kGridMargin = 0.05f;
160     // Fuzziness for float inequality tests
161     constexpr static float kFloatFuzz = 1e-4;
162 
163     // Single implementation for various mapCorrectedToRaw methods
164     template<typename T>
165     status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount, bool clamp, bool simple) const;
166 
167     // Simple linear interpolation option
168     template<typename T>
169     status_t mapCorrectedToRawImplSimple(T* coordPairs, int coordCount, bool clamp) const;
170 
171     status_t mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount, bool clamp) const;
172 
173     // Utility to create reverse mapping grids
174     status_t buildGrids();
175 
176 
177     bool mValidMapping;
178     bool mValidGrids;
179 
180     // intrisic parameters, in pixels
181     float mFx, mFy, mCx, mCy, mS;
182     // pre-calculated inverses for speed
183     float mInvFx, mInvFy;
184     // radial/tangential distortion parameters
185     std::array<float, 5> mK;
186 
187     // pre-correction active array dimensions
188     float mArrayWidth, mArrayHeight;
189     // active array dimensions
190     float mActiveWidth, mActiveHeight;
191     // corner offsets between pre-correction and active arrays
192     float mArrayDiffX, mArrayDiffY;
193 
194     std::vector<GridQuad> mCorrectedGrid;
195     std::vector<GridQuad> mDistortedGrid;
196 
197 }; // class DistortionMapper
198 
199 } // namespace camera3
200 
201 } // namespace android
202 
203 #endif
204