Merge "DngCreator: scale lens distortion paramters" into qt-dev
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -976,6 +977,153 @@ static status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void undistort(/*inout*/double& x, /*inout*/double& y,
|
||||||
|
const std::array<float, 6>& distortion,
|
||||||
|
const float cx, const float cy, const float f) {
|
||||||
|
double xp = (x - cx) / f;
|
||||||
|
double yp = (y - cy) / f;
|
||||||
|
|
||||||
|
double x2 = xp * xp;
|
||||||
|
double y2 = yp * yp;
|
||||||
|
double r2 = x2 + y2;
|
||||||
|
double xy2 = 2.0 * xp * yp;
|
||||||
|
|
||||||
|
const float k0 = distortion[0];
|
||||||
|
const float k1 = distortion[1];
|
||||||
|
const float k2 = distortion[2];
|
||||||
|
const float k3 = distortion[3];
|
||||||
|
const float p1 = distortion[4];
|
||||||
|
const float p2 = distortion[5];
|
||||||
|
|
||||||
|
double kr = k0 + ((k3 * r2 + k2) * r2 + k1) * r2;
|
||||||
|
double xpp = xp * kr + p1 * xy2 + p2 * (r2 + 2.0 * x2);
|
||||||
|
double ypp = yp * kr + p1 * (r2 + 2.0 * y2) + p2 * xy2;
|
||||||
|
|
||||||
|
x = xpp * f + cx;
|
||||||
|
y = ypp * f + cy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool unDistortWithinPreCorrArray(
|
||||||
|
double x, double y,
|
||||||
|
const std::array<float, 6>& distortion,
|
||||||
|
const float cx, const float cy, const float f,
|
||||||
|
int preCorrW, int preCorrH) {
|
||||||
|
undistort(x, y, distortion, cx, cy, f);
|
||||||
|
if (x < 0.0 || y < 0.0 || x > preCorrW - 1 || y > preCorrH - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool boxWithinPrecorrectionArray(
|
||||||
|
int left, int top, int right, int bottom,
|
||||||
|
const std::array<float, 6>& distortion,
|
||||||
|
const float& cx, const float& cy, const float& f,
|
||||||
|
const int& preCorrW, const int& preCorrH){
|
||||||
|
// Top row
|
||||||
|
if (!unDistortWithinPreCorrArray(left, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unDistortWithinPreCorrArray(cx, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unDistortWithinPreCorrArray(right, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middle row
|
||||||
|
if (!unDistortWithinPreCorrArray(left, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unDistortWithinPreCorrArray(right, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom row
|
||||||
|
if (!unDistortWithinPreCorrArray(left, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unDistortWithinPreCorrArray(cx, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unDistortWithinPreCorrArray(right, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool scaledBoxWithinPrecorrectionArray(
|
||||||
|
double scale/*must be <= 1.0*/,
|
||||||
|
const std::array<float, 6>& distortion,
|
||||||
|
const float cx, const float cy, const float f,
|
||||||
|
const int preCorrW, const int preCorrH){
|
||||||
|
|
||||||
|
double left = cx * (1.0 - scale);
|
||||||
|
double right = (preCorrW - 1) * scale + cx * (1.0 - scale);
|
||||||
|
double top = cy * (1.0 - scale);
|
||||||
|
double bottom = (preCorrH - 1) * scale + cy * (1.0 - scale);
|
||||||
|
|
||||||
|
return boxWithinPrecorrectionArray(left, top, right, bottom,
|
||||||
|
distortion, cx, cy, f, preCorrW, preCorrH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static status_t findPostCorrectionScale(
|
||||||
|
double stepSize, double minScale,
|
||||||
|
const std::array<float, 6>& distortion,
|
||||||
|
const float cx, const float cy, const float f,
|
||||||
|
const int preCorrW, const int preCorrH,
|
||||||
|
/*out*/ double* outScale) {
|
||||||
|
if (outScale == nullptr) {
|
||||||
|
ALOGE("%s: outScale must not be null", __FUNCTION__);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (double scale = 1.0; scale > minScale; scale -= stepSize) {
|
||||||
|
if (scaledBoxWithinPrecorrectionArray(
|
||||||
|
scale, distortion, cx, cy, f, preCorrW, preCorrH)) {
|
||||||
|
*outScale = scale;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ALOGE("%s: cannot find cropping scale for lens distortion: stepSize %f, minScale %f",
|
||||||
|
__FUNCTION__, stepSize, minScale);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply a scale factor to distortion coefficients so that the image is zoomed out and all pixels
|
||||||
|
// are sampled within the precorrection array
|
||||||
|
static void normalizeLensDistortion(
|
||||||
|
/*inout*/std::array<float, 6>& distortion,
|
||||||
|
float cx, float cy, float f, int preCorrW, int preCorrH) {
|
||||||
|
ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)",
|
||||||
|
__FUNCTION__, distortion[0], distortion[1], distortion[2],
|
||||||
|
distortion[3], distortion[4], distortion[5],
|
||||||
|
cx, cy, f, preCorrW, preCorrH);
|
||||||
|
|
||||||
|
// Only update distortion coeffients if we can find a good bounding box
|
||||||
|
double scale = 1.0;
|
||||||
|
if (OK == findPostCorrectionScale(0.002, 0.5,
|
||||||
|
distortion, cx, cy, f, preCorrW, preCorrH,
|
||||||
|
/*out*/&scale)) {
|
||||||
|
ALOGV("%s: scaling distortion coefficients by %f", __FUNCTION__, scale);
|
||||||
|
// The formula:
|
||||||
|
// xc = xi * (k0 + k1*r^2 + k2*r^4 + k3*r^6) + k4 * (2*xi*yi) + k5 * (r^2 + 2*xi^2)
|
||||||
|
// To create effective zoom we want to replace xi by xi *m, yi by yi*m and r^2 by r^2*m^2
|
||||||
|
// Factor the extra m power terms into k0~k6
|
||||||
|
std::array<float, 6> scalePowers = {1, 3, 5, 7, 2, 2};
|
||||||
|
for (size_t i = 0; i < 6; i++) {
|
||||||
|
distortion[i] *= pow(scale, scalePowers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@@ -1086,9 +1234,9 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
|
|||||||
uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
|
uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
|
||||||
|
|
||||||
if (!((imageWidth == preWidth && imageHeight == preHeight) ||
|
if (!((imageWidth == preWidth && imageHeight == preHeight) ||
|
||||||
(imageWidth == pixWidth && imageHeight == pixHeight))) {
|
(imageWidth == pixWidth && imageHeight == pixHeight))) {
|
||||||
jniThrowException(env, "java/lang/AssertionError",
|
jniThrowException(env, "java/lang/AssertionError",
|
||||||
"Height and width of imate buffer did not match height and width of"
|
"Height and width of image buffer did not match height and width of"
|
||||||
"either the preCorrectionActiveArraySize or the pixelArraySize.");
|
"either the preCorrectionActiveArraySize or the pixelArraySize.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -1793,7 +1941,7 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
|
|||||||
status_t err = OK;
|
status_t err = OK;
|
||||||
|
|
||||||
// Set up rectilinear distortion correction
|
// Set up rectilinear distortion correction
|
||||||
float distortion[6] {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
std::array<float, 6> distortion = {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
||||||
bool gotDistortion = false;
|
bool gotDistortion = false;
|
||||||
|
|
||||||
camera_metadata_entry entry4 =
|
camera_metadata_entry entry4 =
|
||||||
@@ -1810,6 +1958,19 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
|
|||||||
results.find(ANDROID_LENS_DISTORTION);
|
results.find(ANDROID_LENS_DISTORTION);
|
||||||
if (entry3.count == 5) {
|
if (entry3.count == 5) {
|
||||||
gotDistortion = true;
|
gotDistortion = true;
|
||||||
|
|
||||||
|
|
||||||
|
// Scale the distortion coefficients to create a zoom in warpped image so that all
|
||||||
|
// pixels are drawn within input image.
|
||||||
|
for (size_t i = 0; i < entry3.count; i++) {
|
||||||
|
distortion[i+1] = entry3.data.f[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO b/118690688: deal with the case where RAW size != preCorrSize
|
||||||
|
if (preWidth == imageWidth && preHeight == imageHeight) {
|
||||||
|
normalizeLensDistortion(distortion, cx, cy, f, preWidth, preHeight);
|
||||||
|
}
|
||||||
|
|
||||||
float m_x = std::fmaxf(preWidth-1 - cx, cx);
|
float m_x = std::fmaxf(preWidth-1 - cx, cx);
|
||||||
float m_y = std::fmaxf(preHeight-1 - cy, cy);
|
float m_y = std::fmaxf(preHeight-1 - cy, cy);
|
||||||
float m_sq = m_x*m_x + m_y*m_y;
|
float m_sq = m_x*m_x + m_y*m_y;
|
||||||
@@ -1831,7 +1992,7 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
|
|||||||
m / f
|
m / f
|
||||||
};
|
};
|
||||||
for (size_t i = 0; i < entry3.count; i++) {
|
for (size_t i = 0; i < entry3.count; i++) {
|
||||||
distortion[i+1] = convCoeff[i] * entry3.data.f[i];
|
distortion[i+1] *= convCoeff[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry3 = results.find(ANDROID_LENS_RADIAL_DISTORTION);
|
entry3 = results.find(ANDROID_LENS_RADIAL_DISTORTION);
|
||||||
@@ -1859,8 +2020,8 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gotDistortion) {
|
if (gotDistortion) {
|
||||||
err = builder.addWarpRectilinearForMetadata(distortion, preWidth, preHeight, cx,
|
err = builder.addWarpRectilinearForMetadata(
|
||||||
cy);
|
distortion.data(), preWidth, preHeight, cx, cy);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
|
ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
|
||||||
jniThrowRuntimeException(env, "failed to add distortion correction.");
|
jniThrowRuntimeException(env, "failed to add distortion correction.");
|
||||||
|
|||||||
Reference in New Issue
Block a user