From 0f212b73e47ef0e1fa39aa250ebabedb9d81a361 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 5 Jun 2015 17:03:05 -0700 Subject: Add distortion correction opcodes in DngCreator. Bug: 20491394 Change-Id: Ide932d49e620c7dc9a847bb5ddc8715d5f936bd5 --- media/img_utils/include/img_utils/DngUtils.h | 37 +++++++++++ media/img_utils/src/DngUtils.cpp | 97 +++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) (limited to 'media/img_utils') diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h index 4389b02..3dcedc5 100644 --- a/media/img_utils/include/img_utils/DngUtils.h +++ b/media/img_utils/include/img_utils/DngUtils.h @@ -31,6 +31,7 @@ namespace android { namespace img_utils { #define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0]))) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) /** * Utility class for building values for the OpcodeList tags specified @@ -107,13 +108,49 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase { uint32_t mapPlanes, const float* mapGains); + /** + * Add WarpRectilinear opcode for the given metadata parameters. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addWarpRectilinearForMetadata(const float* kCoeffs, + uint32_t activeArrayWidth, + uint32_t activeArrayHeight, + float opticalCenterX, + float opticalCenterY); + + /** + * Add a WarpRectilinear opcode. + * + * numPlanes - Number of planes included in this opcode. + * opticalCenterX, opticalCenterY - Normalized x,y coordinates of the sensor optical + * center relative to the top,left pixel of the produced images (e.g. [0.5, 0.5] + * gives a sensor optical center in the image center. + * kCoeffs - A list of coefficients for the polynomial equation representing the distortion + * correction. For each plane, 6 coefficients must be included: + * {k_r0, k_r1, k_r2, k_r3, k_t0, k_t1}. See the DNG 1.4 specification for an + * outline of the polynomial used here. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addWarpRectilinear(uint32_t numPlanes, + double opticalCenterX, + double opticalCenterY, + const double* kCoeffs); + // TODO: Add other Opcode methods protected: static const uint32_t FLAG_OPTIONAL = 0x1u; static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u; + // Opcode IDs enum { + WARP_RECTILINEAR_ID = 1, GAIN_MAP_ID = 9, + }; + + // LSM mosaic indices + enum { LSM_R_IND = 0, LSM_GE_IND = 1, LSM_GO_IND = 2, diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp index d3b4a35..b213403 100644 --- a/media/img_utils/src/DngUtils.cpp +++ b/media/img_utils/src/DngUtils.cpp @@ -16,6 +16,10 @@ #include +#include + +#include + namespace android { namespace img_utils { @@ -229,7 +233,7 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top, err = mEndianOut.write(version, 0, NELEMS(version)); if (err != OK) return err; - // Do not include optional flag for preview, as this can have a large effect on the output. + // Allow this opcode to be skipped if not supported uint32_t flags = FLAG_OPTIONAL; err = mEndianOut.write(&flags, 0, 1); @@ -278,5 +282,96 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top, return OK; } +status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs, + uint32_t activeArrayWidth, + uint32_t activeArrayHeight, + float opticalCenterX, + float opticalCenterY) { + if (activeArrayWidth <= 1 || activeArrayHeight <= 1) { + ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32, + __FUNCTION__, activeArrayWidth, activeArrayHeight); + return BAD_VALUE; + } + + double normalizedOCX = opticalCenterX / static_cast(activeArrayWidth - 1); + double normalizedOCY = opticalCenterY / static_cast(activeArrayHeight - 1); + + normalizedOCX = CLAMP(normalizedOCX, 0, 1); + normalizedOCY = CLAMP(normalizedOCY, 0, 1); + + // Conversion factors from Camera2 K factors to DNG spec. K factors: + // + // Note: these are necessary because our unit system assumes a + // normalized max radius of sqrt(2), whereas the DNG spec's + // WarpRectilinear opcode assumes a normalized max radius of 1. + // Thus, each K coefficient must include the domain scaling + // factor (the DNG domain is scaled by sqrt(2) to emulate the + // domain used by the Camera2 specification). + + const double c_0 = sqrt(2); + const double c_1 = 2 * sqrt(2); + const double c_2 = 4 * sqrt(2); + const double c_3 = 8 * sqrt(2); + const double c_4 = 2; + const double c_5 = 2; + + const double coeffs[] = { c_0 * kCoeffs[0], + c_1 * kCoeffs[1], + c_2 * kCoeffs[2], + c_3 * kCoeffs[3], + c_4 * kCoeffs[4], + c_5 * kCoeffs[5] }; + + + return addWarpRectilinear(/*numPlanes*/1, + /*opticalCenterX*/normalizedOCX, + /*opticalCenterY*/normalizedOCY, + coeffs); +} + +status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, + double opticalCenterX, + double opticalCenterY, + const double* kCoeffs) { + + uint32_t opcodeId = WARP_RECTILINEAR_ID; + + status_t err = mEndianOut.write(&opcodeId, 0, 1); + if (err != OK) return err; + + uint8_t version[] = {1, 3, 0, 0}; + err = mEndianOut.write(version, 0, NELEMS(version)); + if (err != OK) return err; + + // Allow this opcode to be skipped if not supported + uint32_t flags = FLAG_OPTIONAL; + + err = mEndianOut.write(&flags, 0, 1); + if (err != OK) return err; + + const uint32_t NUMBER_CENTER_ARGS = 2; + const uint32_t NUMBER_COEFFS = numPlanes * 6; + uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t); + + err = mEndianOut.write(&totalSize, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(&numPlanes, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS); + if (err != OK) return err; + + err = mEndianOut.write(&opticalCenterX, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(&opticalCenterY, 0, 1); + if (err != OK) return err; + + mCount++; + + return OK; +} + } /*namespace img_utils*/ } /*namespace android*/ -- cgit v1.1