/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SERVERS_DISTORTIONMAPPER_H #define ANDROID_SERVERS_DISTORTIONMAPPER_H #include #include #include #include "camera/CameraMetadata.h" #include "device3/CoordinateMapper.h" namespace android { namespace camera3 { /** * Utilities to transform between raw (distorted) and warped (corrected) coordinate systems * for cameras that support geometric distortion */ class DistortionMapper : public CoordinateMapper { public: DistortionMapper(); DistortionMapper(const DistortionMapper& other) : mDistortionMapperInfo(other.mDistortionMapperInfo), mDistortionMapperInfoMaximumResolution(other.mDistortionMapperInfoMaximumResolution) { initRemappedKeys(); } void initRemappedKeys() override; /** * Check whether distortion correction is supported by the camera HAL */ static bool isDistortionSupported(const CameraMetadata &deviceInfo); /** * Update static lens calibration info from camera characteristics */ status_t setupStaticInfo(const CameraMetadata &deviceInfo); /** * Return whether distortion correction can be applied currently */ bool calibrationValid() const; /** * Correct capture request if distortion correction is enabled */ status_t correctCaptureRequest(CameraMetadata *request); /** * Correct capture result if distortion correction is enabled */ status_t correctCaptureResult(CameraMetadata *request); public: // Visible for testing. Not guarded by mutex; do not use concurrently struct DistortionMapperInfo; /** * Update lens calibration from capture results or equivalent */ status_t updateCalibration(const CameraMetadata &result, bool isStatic = false, bool maxResolution = false); /** * Transform from distorted (original) to corrected (warped) coordinates. * Coordinates are transformed in-place * * coordPairs: A pointer to an array of consecutive (x,y) points * coordCount: Number of (x,y) pairs to transform * clamp: Whether to clamp the result to the bounds of the active array * simple: Whether to do complex correction or just a simple linear map */ status_t mapRawToCorrected(int32_t *coordPairs, int coordCount, DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true); /** * Transform from distorted (original) to corrected (warped) coordinates. * Coordinates are transformed in-place * * rects: A pointer to an array of consecutive (x,y, w, h) rectangles * rectCount: Number of rectangles to transform * clamp: Whether to clamp the result to the bounds of the active array * simple: Whether to do complex correction or just a simple linear map */ status_t mapRawRectToCorrected(int32_t *rects, int rectCount, DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true); /** * Transform from corrected (warped) to distorted (original) coordinates. * Coordinates are transformed in-place * * coordPairs: A pointer to an array of consecutive (x,y) points * coordCount: Number of (x,y) pairs to transform * clamp: Whether to clamp the result to the bounds of the precorrection active array * simple: Whether to do complex correction or just a simple linear map */ status_t mapCorrectedToRaw(int32_t* coordPairs, int coordCount, const DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true) const; /** * Transform from corrected (warped) to distorted (original) coordinates. * Coordinates are transformed in-place * * rects: A pointer to an array of consecutive (x,y, w, h) rectangles * rectCount: Number of rectangles to transform * clamp: Whether to clamp the result to the bounds of the precorrection active array * simple: Whether to do complex correction or just a simple linear map */ status_t mapCorrectedRectToRaw(int32_t *rects, int rectCount, const DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true) const; struct GridQuad { // Source grid quad, or null const GridQuad *src; // x,y coordinates of corners, in // clockwise order std::array coords; }; struct DistortionMapperInfo { bool mValidMapping = false; bool mValidGrids = false; // intrisic parameters, in pixels float mFx, mFy, mCx, mCy, mS; // pre-calculated inverses for speed float mInvFx, mInvFy; // radial/tangential distortion parameters std::array mK; // pre-correction active array dimensions float mArrayWidth, mArrayHeight; // active array dimensions float mActiveWidth, mActiveHeight; // corner offsets between pre-correction and active arrays float mArrayDiffX, mArrayDiffY; std::vector mCorrectedGrid; std::vector mDistortedGrid; }; // Find which grid quad encloses the point; returns null if none do static const GridQuad* findEnclosingQuad( const int32_t pt[2], const std::vector& grid); // Calculate 'horizontal' interpolation coordinate for the point and the quad // Assumes the point P is within the quad Q. // Given quad with points P1-P4, and edges E12-E41, and considering the edge segments as // functions of U: E12(u), where E12(0) = P1 and E12(1) = P2, then we want to find a u // such that the edge E12(u) -> E43(u) contains point P. // This can be determined by checking if the cross product of vector [E12(u)-E43(u)] and // vector [E12(u)-P] is zero. Solving the equation // [E12(u)-E43(u)] x [E12(u)-P] = 0 gives a quadratic equation in u; the solution in the range // 0 to 1 is the one chosen. // If calculateU is true, then an interpolation coordinate for edges E12 and E43 is found; // if it is false, then an interpolation coordinate for edges E14 and E23 is found. static float calculateUorV(const int32_t pt[2], const GridQuad& quad, bool calculateU); DistortionMapperInfo *getMapperInfo(bool maxResolution = false) { return maxResolution ? &mDistortionMapperInfoMaximumResolution : &mDistortionMapperInfo; }; private: mutable std::mutex mMutex; // Number of quads in each dimension of the mapping grids constexpr static size_t kGridSize = 15; // Margin to expand the grid by to ensure it doesn't clip the domain constexpr static float kGridMargin = 0.05f; // Fuzziness for float inequality tests constexpr static float kFloatFuzz = 1e-4; bool mMaxResolution = false; status_t setupStaticInfoLocked(const CameraMetadata &deviceInfo, bool maxResolution); // Single implementation for various mapCorrectedToRaw methods template status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount, const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const; // Simple linear interpolation option template status_t mapCorrectedToRawImplSimple(T* coordPairs, int coordCount, const DistortionMapperInfo *mapperInfo, bool clamp) const; status_t mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount, const DistortionMapperInfo *mapperInfo, bool clamp) const; // Utility to create reverse mapping grids status_t buildGrids(DistortionMapperInfo *mapperInfo); DistortionMapperInfo mDistortionMapperInfo; DistortionMapperInfo mDistortionMapperInfoMaximumResolution; }; // class DistortionMapper } // namespace camera3 } // namespace android #endif