blob: 96f4fdafaa2f9b3804271966e2821c452ecd3726 [file] [log] [blame]
/*
* 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 <utils/Errors.h>
#include <array>
#include <mutex>
#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<float, 8> 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<float, 5> 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<GridQuad> mCorrectedGrid;
std::vector<GridQuad> 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<GridQuad>& 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<typename T>
status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount,
const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const;
// Simple linear interpolation option
template<typename T>
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