1308 lines
55 KiB
C++
1308 lines
55 KiB
C++
#include "G3D/ImageFormat.h"
|
|
#include "G3D/Color1unorm8.h"
|
|
#include "G3D/Color3unorm8.h"
|
|
#include "G3D/Color4unorm8.h"
|
|
#include "G3D/Color1.h"
|
|
#include "G3D/Color3.h"
|
|
#include "G3D/Color4.h"
|
|
|
|
|
|
namespace G3D {
|
|
|
|
// this is the signature for all conversion routines (same parameters as ImageFormat::convert)
|
|
typedef void (*ConvertFunc)(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg);
|
|
|
|
// this defines the conversion routines for converting between compatible formats
|
|
static const int NUM_CONVERT_IMAGE_FORMATS = 5;
|
|
struct ConvertAttributes {
|
|
ConvertFunc m_converter;
|
|
ImageFormat::Code m_sourceFormats[NUM_CONVERT_IMAGE_FORMATS];
|
|
ImageFormat::Code m_destFormats[NUM_CONVERT_IMAGE_FORMATS];
|
|
bool m_handlesSourcePadding;
|
|
bool m_handlesDestPadding;
|
|
bool m_handleInvertY;
|
|
};
|
|
|
|
// forward declare the converters we can use them below
|
|
#define DECLARE_CONVERT_FUNC(name) static void name(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg);
|
|
|
|
DECLARE_CONVERT_FUNC(l8_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(l32f_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_rgba8);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_bgr8);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(bgr8_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(bgr8_to_rgba8);
|
|
DECLARE_CONVERT_FUNC(bgr8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(rgba8_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(rgba8_to_bgr8);
|
|
DECLARE_CONVERT_FUNC(rgba8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(rgb32f_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_rgba8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_bgr8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_rgb32f);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_bayer_rggb8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_bayer_gbrg8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_bayer_grbg8);
|
|
DECLARE_CONVERT_FUNC(rgba32f_to_bayer_bggr8);
|
|
DECLARE_CONVERT_FUNC(bayer_rggb8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(bayer_gbrg8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(bayer_grbg8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(bayer_bggr8_to_rgba32f);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_yuv420p);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_yuv422);
|
|
DECLARE_CONVERT_FUNC(rgb8_to_yuv444);
|
|
DECLARE_CONVERT_FUNC(yuv420p_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(yuv422_to_rgb8);
|
|
DECLARE_CONVERT_FUNC(yuv444_to_rgb8);
|
|
|
|
// this is the list of mappings between formats and the routines to perform them
|
|
static const ConvertAttributes sConvertMappings[] = {
|
|
|
|
// RGB -> RGB color space
|
|
// L8 ->
|
|
{l8_to_rgb8, {ImageFormat::CODE_L8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, true},
|
|
|
|
// L32F ->
|
|
{l32f_to_rgb8, {ImageFormat::CODE_L32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, true},
|
|
|
|
// RGB8 ->
|
|
{rgb8_to_rgba8, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{rgb8_to_bgr8, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{rgb8_to_rgba32f, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, true, false, true},
|
|
|
|
// BGR8 ->
|
|
{bgr8_to_rgb8, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{bgr8_to_rgba8, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{bgr8_to_rgba32f, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, true, false, true},
|
|
|
|
// RGBA8 ->
|
|
{rgba8_to_rgb8, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{rgba8_to_bgr8, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, false, false, true},
|
|
{rgba8_to_rgba32f, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, true, false, true},
|
|
|
|
// RGB32F ->
|
|
{rgb32f_to_rgba32f, {ImageFormat::CODE_RGB32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, true, false, true},
|
|
|
|
// RGBA32F ->
|
|
{rgba32f_to_rgb8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_rgba8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_bgr8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BGR8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_rgb32f, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB32F, ImageFormat::CODE_NONE}, false, true, true},
|
|
|
|
// RGB -> BAYER color space
|
|
{rgba32f_to_bayer_rggb8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BAYER_RGGB8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_bayer_gbrg8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BAYER_GBRG8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_bayer_grbg8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BAYER_GRBG8, ImageFormat::CODE_NONE}, false, true, true},
|
|
{rgba32f_to_bayer_bggr8, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, {ImageFormat::CODE_BAYER_BGGR8, ImageFormat::CODE_NONE}, false, true, true},
|
|
|
|
// BAYER -> RGB color space
|
|
{bayer_rggb8_to_rgba32f, {ImageFormat::CODE_BAYER_RGGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, false, false, true},
|
|
{bayer_gbrg8_to_rgba32f, {ImageFormat::CODE_BAYER_GBRG8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, false, false, true},
|
|
{bayer_grbg8_to_rgba32f, {ImageFormat::CODE_BAYER_GRBG8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, false, false, true},
|
|
{bayer_bggr8_to_rgba32f, {ImageFormat::CODE_BAYER_BGGR8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGBA32F, ImageFormat::CODE_NONE}, false, false, true},
|
|
|
|
// RGB <-> YUV color space
|
|
{rgb8_to_yuv420p, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_YUV420_PLANAR, ImageFormat::CODE_NONE}, false, false, false},
|
|
{rgb8_to_yuv422, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_YUV422, ImageFormat::CODE_NONE}, false, false, false},
|
|
{rgb8_to_yuv444, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, {ImageFormat::CODE_YUV444, ImageFormat::CODE_NONE}, false, false, false},
|
|
{yuv420p_to_rgb8, {ImageFormat::CODE_YUV420_PLANAR, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, false},
|
|
{yuv422_to_rgb8, {ImageFormat::CODE_YUV422, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, false},
|
|
{yuv444_to_rgb8, {ImageFormat::CODE_YUV444, ImageFormat::CODE_NONE}, {ImageFormat::CODE_RGB8, ImageFormat::CODE_NONE}, false, false, false},
|
|
};
|
|
|
|
static ConvertFunc findConverter(TextureFormat::Code sourceCode, TextureFormat::Code destCode, bool needsSourcePadding, bool needsDestPadding, bool needsInvertY) {
|
|
int numRoutines = sizeof(sConvertMappings) / sizeof(ConvertAttributes);
|
|
for (int routineIndex = 0; routineIndex < numRoutines; ++routineIndex) {
|
|
int sourceIndex = 0;
|
|
ConvertAttributes routine = sConvertMappings[routineIndex];
|
|
|
|
while (routine.m_sourceFormats[sourceIndex] != ImageFormat::CODE_NONE) {
|
|
// check for matching source
|
|
if (routine.m_sourceFormats[sourceIndex] == sourceCode) {
|
|
int destIndex = 0;
|
|
|
|
// now check for matching dest to see if the routine fits
|
|
while (routine.m_destFormats[destIndex] != ImageFormat::CODE_NONE) {
|
|
|
|
// check if dest format matches and padding + invert rules match
|
|
if ((routine.m_destFormats[destIndex] == destCode) &&
|
|
(!needsSourcePadding || (routine.m_handlesSourcePadding == needsSourcePadding)) &&
|
|
(!needsDestPadding || (routine.m_handlesDestPadding == needsDestPadding)) &&
|
|
(!needsInvertY || (routine.m_handleInvertY == needsInvertY))) {
|
|
|
|
// found compatible converter
|
|
return routine.m_converter;
|
|
}
|
|
++destIndex;
|
|
}
|
|
}
|
|
++sourceIndex;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool conversionAvailable(const ImageFormat* srcFormat, int srcRowPadBits, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY = false) {
|
|
bool conversionAvailable = false;
|
|
|
|
// check if a conversion is available
|
|
if ( (srcFormat->code == dstFormat->code) && (srcRowPadBits == dstRowPadBits) && !invertY) {
|
|
conversionAvailable = true;
|
|
} else {
|
|
ConvertFunc directConverter = findConverter(srcFormat->code, dstFormat->code, srcRowPadBits > 0, dstRowPadBits > 0, invertY);
|
|
|
|
conversionAvailable = (directConverter != NULL);
|
|
}
|
|
|
|
return conversionAvailable;
|
|
}
|
|
|
|
bool ImageFormat::convert(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits,
|
|
const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits,
|
|
bool invertY, BayerAlgorithm bayerAlg) {
|
|
|
|
bool conversionAvailable = false;
|
|
|
|
// Handle direct copy of image to same format
|
|
if ( (srcFormat->code == dstFormat->code) && (srcRowPadBits == dstRowPadBits) && !invertY) {
|
|
|
|
System::memcpy(dstBytes[0], srcBytes[0], iCeil(((srcWidth * srcFormat->cpuBitsPerPixel + srcRowPadBits) * srcHeight) / 8.0f));
|
|
conversionAvailable = true;
|
|
} else {
|
|
// if no direct conversion routine exists,
|
|
// then look for conversion to intermediate
|
|
// and then from intermediate to dest.
|
|
// intermediate format is RGBA32F
|
|
ConvertFunc directConverter = findConverter(srcFormat->code, dstFormat->code, srcRowPadBits > 0, dstRowPadBits > 0, invertY);
|
|
|
|
// if we have a direct converter, use it, otherwise find intermdiate path
|
|
if (directConverter) {
|
|
directConverter(srcBytes, srcWidth, srcHeight, srcFormat, srcRowPadBits, dstBytes, dstFormat, dstRowPadBits, invertY, bayerAlg);
|
|
conversionAvailable = true;
|
|
} else {
|
|
ConvertFunc toInterConverter = findConverter(srcFormat->code, ImageFormat::CODE_RGBA32F, srcRowPadBits > 0, false, false);;
|
|
ConvertFunc fromInterConverter = findConverter(ImageFormat::CODE_RGBA32F, dstFormat->code, false, dstRowPadBits > 0, invertY);;
|
|
|
|
if (toInterConverter && fromInterConverter) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * ImageFormat::RGBA32F()->cpuBitsPerPixel * 8));
|
|
|
|
toInterConverter(srcBytes, srcWidth, srcHeight, srcFormat, srcRowPadBits, tmp, ImageFormat::RGBA32F(), 0, false, bayerAlg);
|
|
fromInterConverter(reinterpret_cast<Array<const void*>&>(tmp), srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, dstBytes, dstFormat, dstRowPadBits, invertY, bayerAlg);
|
|
|
|
System::free(tmp[0]);
|
|
|
|
conversionAvailable = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return conversionAvailable;
|
|
}
|
|
|
|
|
|
// *******************
|
|
// RGB -> RGB color space conversions
|
|
// *******************
|
|
|
|
// L8 ->
|
|
static void l8_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
(void)bayerAlg;
|
|
(void)dstRowPadBits;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
|
|
dst[i3 + 0] = src[i];
|
|
dst[i3 + 1] = src[i];
|
|
dst[i3 + 2] = src[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// L32F ->
|
|
static void l32f_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
int srcIndex = 0;
|
|
int dstByteOffset = 0;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const float* src = static_cast<const float*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
srcIndex = srcWidth * (srcHeight - y - 1);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
|
|
Color3unorm8& d = *reinterpret_cast<Color3unorm8*>(dst + dstByteOffset);
|
|
const float s = src[srcIndex];
|
|
const unorm8 c(s);
|
|
d = Color3unorm8(c, c, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
// RGB8 ->
|
|
static void rgb8_to_rgba8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
int i4 = i3 + i;
|
|
|
|
dst[i4 + 0] = src[i3 + 0];
|
|
dst[i4 + 1] = src[i3 + 1];
|
|
dst[i4 + 2] = src[i3 + 2];
|
|
dst[i4 + 3] = unorm8::one();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgb8_to_bgr8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
dst[i3 + 0] = src[i3 + 2];
|
|
dst[i3 + 1] = src[i3 + 1];
|
|
dst[i3 + 2] = src[i3 + 0];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgb8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits % 8 == 0, "Source row padding must be a multiple of 8 bits for this format");
|
|
|
|
int dstIndex = 0;
|
|
int srcByteOffset = 0;
|
|
int srcRowPadBytes = srcRowPadBits / 8;
|
|
Color4* dst = static_cast<Color4*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
dstIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 3) {
|
|
const Color3unorm8& s = *reinterpret_cast<const Color3unorm8*>(src + srcByteOffset);
|
|
dst[dstIndex] = Color4(Color3(s), 1.0f);
|
|
}
|
|
srcByteOffset += srcRowPadBytes;
|
|
}
|
|
}
|
|
|
|
// BGR8 ->
|
|
static void bgr8_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
dst[i3 + 0] = src[i3 + 2];
|
|
dst[i3 + 1] = src[i3 + 1];
|
|
dst[i3 + 2] = src[i3 + 0];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void bgr8_to_rgba8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
int i4 = i3 + i;
|
|
|
|
dst[i4 + 0] = src[i3 + 2];
|
|
dst[i4 + 1] = src[i3 + 1];
|
|
dst[i4 + 2] = src[i3 + 0];
|
|
dst[i4 + 3] = unorm8::one();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void bgr8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits % 8 == 0, "Source row padding must be a multiple of 8 bits for this format");
|
|
|
|
int dstIndex = 0;
|
|
int srcByteOffset = 0;
|
|
int srcRowPadBytes = srcRowPadBits / 8;
|
|
Color4* dst = static_cast<Color4*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
dstIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 3) {
|
|
const Color3unorm8& s = *reinterpret_cast<const Color3unorm8*>(src + srcByteOffset);
|
|
dst[dstIndex] = Color4(Color3(s).bgr(), 1.0f);
|
|
}
|
|
srcByteOffset += srcRowPadBytes;
|
|
}
|
|
}
|
|
|
|
// RGBA8 ->
|
|
static void rgba8_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
int i4 = i3 + i;
|
|
|
|
dst[i3 + 0] = src[i4 + 0];
|
|
dst[i3 + 1] = src[i4 + 1];
|
|
dst[i3 + 2] = src[i4 + 2];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgba8_to_bgr8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
int i = (invertY) ? ((srcHeight-1-y) * srcWidth +x) : (y * srcWidth + x);
|
|
int i3 = i * 3;
|
|
int i4 = i3 + i;
|
|
|
|
dst[i3 + 0] = src[i4 + 2];
|
|
dst[i3 + 1] = src[i4 + 1];
|
|
dst[i3 + 2] = src[i4 + 0];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgba8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits % 8 == 0, "Source row padding must be a multiple of 8 bits for this format");
|
|
|
|
int dstIndex = 0;
|
|
int srcByteOffset = 0;
|
|
int srcRowPadBytes = srcRowPadBits / 8;
|
|
Color4* dst = static_cast<Color4*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
dstIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 4) {
|
|
const Color4unorm8& s = *reinterpret_cast<const Color4unorm8*>(src + srcByteOffset);
|
|
dst[dstIndex] = Color4(s);
|
|
}
|
|
srcByteOffset += srcRowPadBytes;
|
|
}
|
|
}
|
|
|
|
// RGB32F ->
|
|
static void rgb32f_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits % 8 == 0, "Source row padding must be a multiple of 8 bits for this format");
|
|
|
|
int dstIndex = 0;
|
|
int srcByteOffset = 0;
|
|
int srcRowPadBytes = srcRowPadBits / 8;
|
|
Color4* dst = static_cast<Color4*>(dstBytes[0]);
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
dstIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++dstIndex, srcByteOffset += 3 * sizeof(float)) {
|
|
const Color3& s = *reinterpret_cast<const Color3*>(src + srcByteOffset);
|
|
dst[dstIndex] = Color4(Color3(s), 1.0f);
|
|
}
|
|
srcByteOffset += srcRowPadBytes;
|
|
}
|
|
}
|
|
|
|
// RGBA32F ->
|
|
static void rgba32f_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(dstRowPadBits % 8 == 0, "Destination row padding must be a multiple of 8 bits for this format");
|
|
|
|
int srcIndex = 0;
|
|
int dstByteOffset = 0;
|
|
int dstRowPadBytes = dstRowPadBits / 8;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const Color4* src = static_cast<const Color4*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
srcIndex = srcWidth * (srcHeight - y - 1);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
|
|
Color3unorm8& d = *reinterpret_cast<Color3unorm8*>(dst + dstByteOffset);
|
|
const Color4& s = src[srcIndex];
|
|
|
|
d = Color3unorm8(s.rgb());
|
|
}
|
|
dstByteOffset += dstRowPadBytes;
|
|
}
|
|
}
|
|
|
|
static void rgba32f_to_rgba8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(dstRowPadBits % 8 == 0, "Destination row padding must be a multiple of 8 bits for this format");
|
|
|
|
int srcIndex = 0;
|
|
int dstByteOffset = 0;
|
|
int dstRowPadBytes = dstRowPadBits / 8;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const Color4* src = static_cast<const Color4*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
srcIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 4) {
|
|
Color4unorm8& d = *reinterpret_cast<Color4unorm8*>(dst + dstByteOffset);
|
|
const Color4& s = src[srcIndex];
|
|
|
|
d = Color4unorm8(s);
|
|
}
|
|
dstByteOffset += dstRowPadBytes;
|
|
}
|
|
}
|
|
|
|
static void rgba32f_to_bgr8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(dstRowPadBits % 8 == 0, "Destination row padding must be a multiple of 8 bits for this format");
|
|
|
|
int srcIndex = 0;
|
|
int dstByteOffset = 0;
|
|
int dstRowPadBytes = dstRowPadBits / 8;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const Color4* src = static_cast<const Color4*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
srcIndex = srcWidth * (srcHeight - y - 1);
|
|
}
|
|
|
|
for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3) {
|
|
Color3unorm8& d = *reinterpret_cast<Color3unorm8*>(dst + dstByteOffset);
|
|
const Color4& s = src[srcIndex];
|
|
|
|
d = Color3unorm8(s.rgb()).bgr();
|
|
}
|
|
dstByteOffset += dstRowPadBytes;
|
|
}
|
|
}
|
|
|
|
static void rgba32f_to_rgb32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(dstRowPadBits % 8 == 0, "Destination row padding must be a multiple of 8 bits for this format");
|
|
|
|
int srcIndex = 0;
|
|
int dstByteOffset = 0;
|
|
int dstRowPadBytes = dstRowPadBits / 8;
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
const Color4* src = static_cast<const Color4*>(srcBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
if (invertY) {
|
|
srcIndex = srcWidth * (srcHeight - 1 - y);
|
|
}
|
|
for (int x = 0; x < srcWidth; ++x, ++srcIndex, dstByteOffset += 3 * sizeof(float)) {
|
|
Color3& d = *reinterpret_cast<Color3*>(dst + dstByteOffset);
|
|
const Color4& s = src[srcIndex];
|
|
d = s.rgb();
|
|
}
|
|
dstByteOffset += dstRowPadBytes;
|
|
}
|
|
}
|
|
|
|
// *******************
|
|
// RGB <-> YUV color space conversions
|
|
// *******************
|
|
|
|
static uint32 blendPixels(uint32 pixel1, uint32 pixel2) {
|
|
static const uint32 rbMask = 0x00FF00FF;
|
|
static const uint32 agMask = 0xFF00FF00;
|
|
|
|
// Compute two color channels at a time. Use >> 1 for fast division by two
|
|
// Using alternating color channels prevents overflow
|
|
const uint32 rb = ((pixel1 & rbMask) + (pixel2 & rbMask)) >> 1;
|
|
|
|
// Shift first to avoid overflow in alpha channel
|
|
const uint32 ag = (((pixel1 & agMask) >> 1) + ((pixel2 & agMask) >> 1));
|
|
|
|
return ((rb & rbMask) | (ag & agMask));
|
|
}
|
|
|
|
#define PIXEL_RGB8_TO_YUV_Y(r, g, b) unorm8::fromBits(iClamp(((66 * r.bits() + 129 * g.bits() + 25 * b.bits() + 128) >> 8) + 16, 0, 255))
|
|
#define PIXEL_RGB8_TO_YUV_U(r, g, b) unorm8::fromBits(iClamp(((-38 * r.bits() - 74 * g.bits() + 112 * b.bits() + 128) >> 8) + 128, 0, 255))
|
|
#define PIXEL_RGB8_TO_YUV_V(r, g, b) unorm8::fromBits(iClamp(((112 * r.bits() - 94 * g.bits() - 18 * b.bits() + 128) >> 8) + 128, 0, 255))
|
|
|
|
static void rgb8_to_yuv420p(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
debugAssertM((srcWidth % 2 == 0) && (srcHeight % 2 == 0), "Source width and height must be a multiple of two");
|
|
|
|
const Color3unorm8* src = static_cast<const Color3unorm8*>(srcBytes[0]);
|
|
|
|
unorm8* dstY = static_cast<unorm8*>(dstBytes[0]);
|
|
unorm8* dstU = static_cast<unorm8*>(dstBytes[1]);
|
|
unorm8* dstV = static_cast<unorm8*>(dstBytes[2]);
|
|
|
|
for (int y = 0; y < srcHeight; y += 2) {
|
|
for (int x = 0; x < srcWidth; x += 2) {
|
|
|
|
// convert 4-pixel block at a time
|
|
int srcPixelOffset0 = y * srcWidth + x;
|
|
int srcPixelOffset1 = srcPixelOffset0 + 1;
|
|
int srcPixelOffset2 = srcPixelOffset0 + srcWidth;
|
|
int srcPixelOffset3 = srcPixelOffset2 + 1;
|
|
|
|
int yIndex = y * srcWidth + x;
|
|
|
|
dstY[yIndex] = PIXEL_RGB8_TO_YUV_Y(src[srcPixelOffset0].r, src[srcPixelOffset0].g, src[srcPixelOffset0].b);
|
|
dstY[yIndex + 1] = PIXEL_RGB8_TO_YUV_Y(src[srcPixelOffset1].r, src[srcPixelOffset1].g, src[srcPixelOffset1].b);
|
|
|
|
yIndex += srcWidth;
|
|
dstY[yIndex] = PIXEL_RGB8_TO_YUV_Y(src[srcPixelOffset2].r, src[srcPixelOffset2].g, src[srcPixelOffset2].b);
|
|
dstY[yIndex + 1] = PIXEL_RGB8_TO_YUV_Y(src[srcPixelOffset3].r, src[srcPixelOffset3].g, src[srcPixelOffset3].b);
|
|
|
|
uint32 blendedPixel = blendPixels(src[srcPixelOffset0].asUInt32(), src[srcPixelOffset2].asUInt32());
|
|
Color3unorm8 uvSrcColor = Color3unorm8::fromARGB(blendedPixel);
|
|
|
|
int uvIndex = y / 2 * srcWidth / 2 + x / 2;
|
|
dstU[uvIndex] = PIXEL_RGB8_TO_YUV_U(uvSrcColor.r, uvSrcColor.g, uvSrcColor.b);
|
|
dstV[uvIndex] = PIXEL_RGB8_TO_YUV_V(uvSrcColor.r, uvSrcColor.g, uvSrcColor.b);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgb8_to_yuv422(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
debugAssertM((srcWidth % 2 == 0), "Source width must be a multiple of two");
|
|
|
|
const Color3unorm8* src = static_cast<const Color3unorm8*>(srcBytes[0]);
|
|
|
|
unorm8* dst = static_cast<unorm8*>(dstBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; x += 2) {
|
|
|
|
// convert 2-pixel horizontal block at a time
|
|
int srcIndex = y * srcWidth + x;
|
|
int dstIndex = srcIndex * 2;
|
|
|
|
uint32 blendedPixel = blendPixels(src[srcIndex].asUInt32(), src[srcIndex + 1].asUInt32());
|
|
Color3unorm8 uvSrcColor = Color3unorm8::fromARGB(blendedPixel);
|
|
|
|
dst[dstIndex] = PIXEL_RGB8_TO_YUV_Y(src[srcIndex].r, src[srcIndex].g, src[srcIndex].b);
|
|
|
|
dst[dstIndex + 1] = PIXEL_RGB8_TO_YUV_U(uvSrcColor.r, uvSrcColor.g, uvSrcColor.b);
|
|
|
|
dst[dstIndex + 2] = PIXEL_RGB8_TO_YUV_Y(src[srcIndex + 1].r, src[srcIndex + 1].g, src[srcIndex + 1].b);
|
|
|
|
dst[dstIndex + 3] = PIXEL_RGB8_TO_YUV_V(uvSrcColor.r, uvSrcColor.g, uvSrcColor.b);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rgb8_to_yuv444(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
|
|
const Color3unorm8* src = static_cast<const Color3unorm8*>(srcBytes[0]);
|
|
|
|
Color3unorm8* dst = static_cast<Color3unorm8*>(dstBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
|
|
// convert 1-pixels at a time
|
|
int index = y * srcWidth + x;
|
|
unorm8 y = PIXEL_RGB8_TO_YUV_Y(src[index].r, src[index].g, src[index].b);
|
|
unorm8 u = PIXEL_RGB8_TO_YUV_U(src[index].r, src[index].g, src[index].b);
|
|
unorm8 v = PIXEL_RGB8_TO_YUV_V(src[index].r, src[index].g, src[index].b);
|
|
|
|
dst[index].r = y;
|
|
dst[index].g = u;
|
|
dst[index].b = v;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define PIXEL_YUV_TO_RGB8_R(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) + 409 * (v.bits() - 128) + 128) >> 8, 0, 255))
|
|
#define PIXEL_YUV_TO_RGB8_G(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) - 100 * (u.bits() - 128) - 208 * (v.bits() - 128) + 128) >> 8, 0, 255))
|
|
#define PIXEL_YUV_TO_RGB8_B(y, u, v) unorm8::fromBits(iClamp((298 * (y.bits() - 16) + 516 * (u.bits() - 128) + 128) >> 8, 0, 255))
|
|
|
|
static void yuv420p_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
debugAssertM((srcWidth % 2 == 0) && (srcHeight % 2 == 0), "Source width and height must be a multiple of two");
|
|
|
|
const unorm8* srcY = static_cast<const unorm8*>(srcBytes[0]);
|
|
const unorm8* srcU = static_cast<const unorm8*>(srcBytes[1]);
|
|
const unorm8* srcV = static_cast<const unorm8*>(srcBytes[2]);
|
|
|
|
Color3unorm8* dst = static_cast<Color3unorm8*>(dstBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; x += 2) {
|
|
|
|
// convert to two rgb pixels in a row
|
|
Color3unorm8* rgb = &dst[y * srcWidth + x];
|
|
|
|
int yOffset = y * srcWidth + x;
|
|
int uvOffset = y / 2 * srcWidth / 2 + x / 2;
|
|
|
|
rgb->r = PIXEL_YUV_TO_RGB8_R(srcY[yOffset], srcU[uvOffset], srcV[uvOffset]);
|
|
rgb->g = PIXEL_YUV_TO_RGB8_G(srcY[yOffset], srcU[uvOffset], srcV[uvOffset]);
|
|
rgb->b = PIXEL_YUV_TO_RGB8_B(srcY[yOffset], srcU[uvOffset], srcV[uvOffset]);
|
|
|
|
rgb += 1;
|
|
rgb->r = PIXEL_YUV_TO_RGB8_R(srcY[yOffset + 1], srcU[uvOffset], srcV[uvOffset]);
|
|
rgb->g = PIXEL_YUV_TO_RGB8_G(srcY[yOffset + 1], srcU[uvOffset], srcV[uvOffset]);
|
|
rgb->b = PIXEL_YUV_TO_RGB8_B(srcY[yOffset + 1], srcU[uvOffset], srcV[uvOffset]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yuv422_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
debugAssertM((srcWidth % 2 == 0), "Source width must be a multiple of two");
|
|
|
|
const unorm8* src = static_cast<const unorm8*>(srcBytes[0]);
|
|
|
|
Color3unorm8* dst = static_cast<Color3unorm8*>(dstBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; x += 2) {
|
|
|
|
// convert to two rgb pixels in a row
|
|
Color3unorm8* rgb = &dst[y * srcWidth + x];
|
|
|
|
const int srcIndex = (y * srcWidth + x) * 2;
|
|
const unorm8 y = src[srcIndex];
|
|
const unorm8 u = src[srcIndex + 1];
|
|
const unorm8 y2 = src[srcIndex + 2];
|
|
const unorm8 v = src[srcIndex + 3];
|
|
|
|
rgb->r = PIXEL_YUV_TO_RGB8_R(y, u, v);
|
|
rgb->g = PIXEL_YUV_TO_RGB8_G(y, u, v);
|
|
rgb->b = PIXEL_YUV_TO_RGB8_B(y, u, v);
|
|
|
|
rgb += 1;
|
|
rgb->r = PIXEL_YUV_TO_RGB8_R(y2, u, v);
|
|
rgb->g = PIXEL_YUV_TO_RGB8_G(y2, u, v);
|
|
rgb->b = PIXEL_YUV_TO_RGB8_B(y2, u, v);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yuv444_to_rgb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
debugAssertM(srcRowPadBits == 0, "Source row padding must be 0 for this format");
|
|
|
|
const Color3unorm8* src = static_cast<const Color3unorm8*>(srcBytes[0]);
|
|
|
|
Color3unorm8* dst = static_cast<Color3unorm8*>(dstBytes[0]);
|
|
|
|
for (int y = 0; y < srcHeight; ++y) {
|
|
for (int x = 0; x < srcWidth; ++x) {
|
|
|
|
// convert to one rgb pixels at a time
|
|
const int index = y * srcWidth + x;
|
|
const Color3unorm8 s = src[index];
|
|
|
|
Color3unorm8& rgb = dst[index];
|
|
rgb.r = PIXEL_YUV_TO_RGB8_R(s.r, s.g, s.b);
|
|
rgb.g = PIXEL_YUV_TO_RGB8_G(s.r, s.g, s.b);
|
|
rgb.b = PIXEL_YUV_TO_RGB8_B(s.r, s.g, s.b);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Bayer conversions
|
|
//
|
|
|
|
// There are two kinds of rows (GR and BG).
|
|
// In each row, there are two kinds of pixels (G/R, B/G).
|
|
// We express the four kinds of INPUT pixels as:
|
|
// GRG, GRG, BGB, BGG
|
|
//
|
|
// There are three kinds of OUTPUT pixels: R, G, B.
|
|
// Thus there are nominally 12 different I/O combinations,
|
|
// but several are impulses because needed output at that
|
|
// location *is* the input (e.g., G_GRG and G_BGG).
|
|
//
|
|
// The following 5x5 row-major filters are named as output_input.
|
|
|
|
// Green
|
|
static const float G_GRR[5][5] =
|
|
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
|
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
|
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
|
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
|
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
|
|
|
static const float G_BGB[5][5] =
|
|
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
|
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
|
{ -1.0f, 2.0f, 4.0f, 2.0f, -1.0f},
|
|
{ 0.0f, 0.0f, 2.0f, 0.0f, 0.0f},
|
|
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
|
|
|
// Red
|
|
//(the caption in the paper is wrong for this case:
|
|
// "R row B column really means R row G column"
|
|
static const float R_GRG[5][5] =
|
|
{{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f},
|
|
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
|
{ -1.0f, 4.0f, 5.0f, 4.0f, -1.0f},
|
|
{ 0.0f, -1.0f, 0.0f, -1.0f, 0.0f},
|
|
{ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}};
|
|
|
|
static const float R_BGG[5][5] =
|
|
{{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
|
|
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
|
{ 0.5f, 0.0f, 5.0f, 0.0f, 0.5f},
|
|
{ 0.0f, -1.0f, 4.0f, -1.0f, 0.0f},
|
|
{ 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}};
|
|
|
|
static const float R_BGB[5][5] =
|
|
{{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f},
|
|
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
|
{-3.0f/2.0f, 0.0f, 6.0f, 0.0f, -3.0f/2.0f},
|
|
{ 0.0f, 2.0f, 0.0f, 2.0f, 0.0f},
|
|
{ 0.0f, 0.0f, -3.0f/2.0f, 0.0f, 0.0f}};
|
|
|
|
|
|
// Blue
|
|
//(the caption in the paper is wrong for this case:
|
|
// "B row R column really means B row G column")
|
|
#define B_BGG R_GRG
|
|
#define B_GRG R_BGG
|
|
#define B_GRR R_BGB
|
|
|
|
// =====================================================================
|
|
// Helper methods
|
|
// =====================================================================
|
|
|
|
|
|
/** Applies a 5x5 filter to monochrome image I (wrapping at the boundaries) */
|
|
static unorm8 applyFilter(const unorm8* I,
|
|
int x,
|
|
int y,
|
|
int w,
|
|
int h,
|
|
const float filter[5][5]) {
|
|
|
|
debugAssert(isEven(w));
|
|
debugAssert(isEven(h));
|
|
|
|
float sum = 0.0f;
|
|
float denom = 0.0f;
|
|
|
|
for (int dy = 0; dy < 5; ++dy) {
|
|
int offset = ((y + dy + h - 2) % h) * w;
|
|
|
|
for (int dx = 0; dx < 5; ++dx) {
|
|
float f = filter[dy][dx];
|
|
sum += f * (float)I[((x + dx + w - 2) % w) + offset];
|
|
denom += f;
|
|
}
|
|
}
|
|
|
|
return unorm8(sum / denom);
|
|
}
|
|
|
|
/** Helper method for Bayer grbg and bggr --> rgb8 */
|
|
static void swapRedAndBlue(int N, Color3unorm8* out) {
|
|
for (int i = N - 1; i >= 0; --i) {
|
|
unorm8 tmp = out[i].r;
|
|
out[i].r = out[i].b;
|
|
out[i].b = tmp;
|
|
}
|
|
}
|
|
|
|
// RGB -> BAYER color space
|
|
|
|
// =====================================================================
|
|
// rgb8 --> bayer helpers
|
|
// =====================================================================
|
|
static void rgb8_to_bayer_rggb8(const int w, const int h,
|
|
const unorm8* src, unorm8* dst) {
|
|
Color3unorm8* srcColor = (Color3unorm8*)src;
|
|
Color1unorm8* dstColor = (Color1unorm8*)dst;
|
|
|
|
// Top row pixels
|
|
for (int y = 0; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Top left pixels
|
|
for(int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
|
|
}
|
|
|
|
// Top right pixels
|
|
for(int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
}
|
|
|
|
// Bottom row pixels
|
|
for (int y = 1; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Bottom left pixels
|
|
for (int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
|
|
// Bottom right pixels
|
|
for (int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void rgb8_to_bayer_grbg8(const int w, const int h,
|
|
const unorm8* src, unorm8* dst) {
|
|
Color3unorm8* srcColor = (Color3unorm8*)src;
|
|
Color1unorm8* dstColor = (Color1unorm8*)dst;
|
|
|
|
// Top row pixels
|
|
for (int y = 0; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Top left pixels
|
|
for (int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
|
|
// Top right pixels
|
|
for (int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
|
|
}
|
|
}
|
|
|
|
// Bottom row pixels
|
|
for (int y = 1; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Bottom left pixels
|
|
for (int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
|
|
}
|
|
|
|
// Bottom right pixels
|
|
for (int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void rgb8_to_bayer_bggr8(const int w, const int h,
|
|
const unorm8* src, unorm8* dst) {
|
|
Color3unorm8* srcColor = (Color3unorm8*)src;
|
|
Color1unorm8* dstColor = (Color1unorm8*)dst;
|
|
|
|
// Top row pixels
|
|
for (int y = 0; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Top left pixels
|
|
for (int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
|
|
}
|
|
|
|
// Top right pixels
|
|
for (int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
}
|
|
|
|
// Bottom row pixels
|
|
for (int y = 1; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Bottom left pixels
|
|
for(int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
|
|
// Bottom right pixels
|
|
for(int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void rgb8_to_bayer_gbrg8(const int w, const int h,
|
|
const unorm8* src, unorm8* dst) {
|
|
Color3unorm8* srcColor = (Color3unorm8*)src;
|
|
Color1unorm8* dstColor = (Color1unorm8*)dst;
|
|
|
|
// Top row pixels
|
|
for(int y = 0; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Top left pixels
|
|
for(int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
|
|
// Top right pixels
|
|
for(int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].b);
|
|
}
|
|
}
|
|
|
|
// Bottom row pixels
|
|
for(int y = 1; y < h - 1; y += 2) {
|
|
int offset = y * w;
|
|
|
|
// Bottom left pixels
|
|
for(int x = 0; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].r);
|
|
}
|
|
|
|
// Bottom right pixels
|
|
for(int x = 1; x < w - 1; x += 2) {
|
|
dstColor[x + offset] = Color1unorm8(srcColor[x + offset].g);
|
|
}
|
|
}
|
|
}
|
|
|
|
// =====================================================================
|
|
// rgba32f (-->rgb8) --> bayer converter implementations
|
|
// =====================================================================
|
|
static void rgba32f_to_bayer_rggb8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
|
|
rgb8_to_bayer_rggb8(srcWidth, srcHeight, static_cast<unorm8*>(tmp[0]), static_cast<unorm8*>(dstBytes[0]));
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void rgba32f_to_bayer_gbrg8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
|
|
rgb8_to_bayer_grbg8(srcWidth, srcHeight, static_cast<unorm8*>(tmp[0]), static_cast<unorm8*>(dstBytes[0]));
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void rgba32f_to_bayer_grbg8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
|
|
rgb8_to_bayer_gbrg8(srcWidth, srcHeight, static_cast<unorm8*>(tmp[0]), static_cast<unorm8*>(dstBytes[0]));
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void rgba32f_to_bayer_bggr8(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
rgba32f_to_rgb8(srcBytes, srcWidth, srcHeight, ImageFormat::RGBA32F(), 0, tmp, ImageFormat::RGB8(), 0, invertY, bayerAlg);
|
|
rgb8_to_bayer_bggr8(srcWidth, srcHeight, static_cast<unorm8*>(tmp[0]), static_cast<unorm8*>(dstBytes[0]));
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
// BAYER -> RGB color space
|
|
|
|
// =====================================================================
|
|
// bayer --> rgb8 helpers
|
|
// =====================================================================
|
|
static void bayer_rggb8_to_rgb8_mhc(int w, int h,
|
|
const unorm8* in, unorm8* _out) {
|
|
debugAssert(in != _out);
|
|
|
|
Color3unorm8* out = (Color3unorm8*)_out;
|
|
|
|
for (int y = 0; y < h; ++y) {
|
|
|
|
// Row beginning in the input array.
|
|
int offset = y * w;
|
|
|
|
// RG row
|
|
for (int x = 0; x < w; ++x, ++out) {
|
|
// R pixel
|
|
{
|
|
out->r = in[x + offset];
|
|
out->g = applyFilter(in, x, y, w, h, G_GRR);
|
|
out->b = applyFilter(in, x, y, w, h, B_GRR);
|
|
}
|
|
++x; ++out;
|
|
|
|
// G pixel
|
|
{
|
|
out->r = applyFilter(in, x, y, w, h, R_GRG);
|
|
out->g = in[x + offset];
|
|
out->b = applyFilter(in, x, y, w, h, B_GRG);
|
|
}
|
|
}
|
|
|
|
++y;
|
|
offset += w;
|
|
|
|
// GB row
|
|
for (int x = 0; x < w; ++x, ++out) {
|
|
// G pixel
|
|
{
|
|
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
|
out->g = in[x + offset];
|
|
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
|
}
|
|
++x; ++out;
|
|
|
|
// B pixel
|
|
{
|
|
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
|
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
|
out->b = in[x + offset];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void bayer_gbrg8_to_rgb8_mhc(int w, int h,
|
|
const unorm8* in, unorm8* _out) {
|
|
|
|
debugAssert(in != _out);
|
|
|
|
Color3unorm8* out = (Color3unorm8*)_out;
|
|
|
|
for (int y = 0; y < h; ++y) {
|
|
|
|
// Row beginning in the input array.
|
|
int offset = y * w;
|
|
|
|
// GB row
|
|
for (int x = 0; x < w; ++x, ++out) {
|
|
// G pixel
|
|
{
|
|
out->r = applyFilter(in, x, y, w, h, R_BGG);
|
|
out->g = in[x + offset];
|
|
out->b = applyFilter(in, x, y, w, h, B_BGG);
|
|
}
|
|
++x; ++out;
|
|
|
|
// B pixel
|
|
{
|
|
out->r = applyFilter(in, x, y, w, h, R_BGB);
|
|
out->g = applyFilter(in, x, y, w, h, G_BGB);
|
|
out->b = in[x + offset];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void bayer_grbg8_to_rgb8_mhc(int w, int h,
|
|
const unorm8* in, unorm8* _out) {
|
|
// Run the equivalent function for red
|
|
bayer_gbrg8_to_rgb8_mhc(w, h, in, _out);
|
|
|
|
// Now swap red and blue
|
|
swapRedAndBlue(w * h, (Color3unorm8*)_out);
|
|
}
|
|
|
|
|
|
static void bayer_bggr8_to_rgb8_mhc(int w, int h,
|
|
const unorm8* in, unorm8* _out) {
|
|
// Run the equivalent function for red
|
|
bayer_rggb8_to_rgb8_mhc(w, h, in, _out);
|
|
|
|
// Now swap red and blue
|
|
swapRedAndBlue(w * h, (Color3unorm8*)_out);
|
|
}
|
|
|
|
// =====================================================================
|
|
// bayer (--> rgb8) --> rgba32f converter implementations
|
|
// =====================================================================
|
|
static void bayer_rggb8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
bayer_rggb8_to_rgb8_mhc(srcWidth, srcHeight, static_cast<const unorm8*>(srcBytes[0]), static_cast<unorm8*>(tmp[0]));
|
|
rgb8_to_rgba32f(reinterpret_cast<Array<const void*>&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void bayer_gbrg8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
bayer_grbg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast<const unorm8*>(srcBytes[0]), static_cast<unorm8*>(tmp[0]));
|
|
rgb8_to_rgba32f(reinterpret_cast<Array<const void*>&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void bayer_grbg8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
bayer_gbrg8_to_rgb8_mhc(srcWidth, srcHeight, static_cast<const unorm8*>(srcBytes[0]), static_cast<unorm8*>(tmp[0]));
|
|
rgb8_to_rgba32f(reinterpret_cast<Array<const void*>&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
static void bayer_bggr8_to_rgba32f(const Array<const void*>& srcBytes, int srcWidth, int srcHeight, const ImageFormat* srcFormat, int srcRowPadBits, const Array<void*>& dstBytes, const ImageFormat* dstFormat, int dstRowPadBits, bool invertY, ImageFormat::BayerAlgorithm bayerAlg) {
|
|
Array<void*> tmp;
|
|
tmp.append(System::malloc(srcWidth * srcHeight * sizeof(Color3unorm8)));
|
|
|
|
bayer_bggr8_to_rgb8_mhc(srcWidth, srcHeight, static_cast<const unorm8*>(srcBytes[0]), static_cast<unorm8*>(tmp[0]));
|
|
rgb8_to_rgba32f(reinterpret_cast<Array<const void*>&>(tmp), srcWidth, srcHeight, ImageFormat::RGB8(), 0, dstBytes, ImageFormat::RGBA32F(), 0, invertY, bayerAlg);
|
|
|
|
System::free(tmp[0]);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: The following region is commented out because so far
|
|
// those conversions are not used anywhere else. Until it is
|
|
// decided that such conversions are not needed, this region
|
|
// remains commented out.
|
|
|
|
|
|
// // =====================================================================
|
|
// // bayer --> bgr8
|
|
// // =====================================================================
|
|
|
|
// static void bayer_rggb8_to_bgr8_mhc(int w, int h,
|
|
// const unorm8* in, unorm8* _out) {
|
|
// debugAssert(in != _out);
|
|
|
|
// Color3unorm8* out = (Color3unorm8*)_out;
|
|
|
|
// for (int y = 0; y < h; ++y) {
|
|
|
|
// // Row beginning in the input array.
|
|
// int offset = y * w;
|
|
|
|
// // RG row
|
|
// for (int x = 0; x < w; ++x, ++out) {
|
|
// // R pixel
|
|
// {
|
|
// out->b = in[x + offset];
|
|
// out->g = applyFilter(in, x, y, w, h, G_GRR);
|
|
// out->r = applyFilter(in, x, y, w, h, B_GRR);
|
|
// }
|
|
// ++x; ++out;
|
|
|
|
// // G pixel
|
|
// {
|
|
// out->b = applyFilter(in, x, y, w, h, R_GRG);
|
|
// out->g = in[x + offset];
|
|
// out->r = applyFilter(in, x, y, w, h, B_GRG);
|
|
// }
|
|
// }
|
|
|
|
// ++y;
|
|
// offset += w;
|
|
|
|
// // GB row
|
|
// for (int x = 0; x < w; ++x, ++out) {
|
|
// // G pixel
|
|
// {
|
|
// out->b = applyFilter(in, x, y, w, h, R_BGG);
|
|
// out->g = in[x + offset];
|
|
// out->r = applyFilter(in, x, y, w, h, B_BGG);
|
|
// }
|
|
// ++x; ++out;
|
|
|
|
// // B pixel
|
|
// {
|
|
// out->b = applyFilter(in, x, y, w, h, R_BGB);
|
|
// out->g = applyFilter(in, x, y, w, h, G_BGB);
|
|
// out->r = in[x + offset];
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// static void bayer_gbrg8_to_bgr8_mhc(int w, int h,
|
|
// const unorm8* in, unorm8* _out) {
|
|
|
|
// debugAssert(in != _out);
|
|
|
|
// Color3unorm8* out = (Color3unorm8*)_out;
|
|
|
|
// for (int y = 0; y < h; ++y) {
|
|
|
|
// // Row beginning in the input array.
|
|
// int offset = y * w;
|
|
|
|
// // GB row
|
|
// for (int x = 0; x < srcWidth; ++x, ++out) {
|
|
// // G pixel
|
|
// {
|
|
// out->b = applyFilter(in, x, y, w, h, R_BGG);
|
|
// out->g = in[x + offset];
|
|
// out->r = applyFilter(in, x, y, w, h, B_BGG);
|
|
// }
|
|
// ++x; ++out;
|
|
|
|
// // B pixel
|
|
// {
|
|
// out->b = applyFilter(in, x, y, w, h, R_BGB);
|
|
// out->g = applyFilter(in, x, y, w, h, G_BGB);
|
|
// out->r = in[x + offset];
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// static void bayer_grbg8_to_bgr8_mhc(int w, int h,
|
|
// const unorm8* in, unorm8* _out) {
|
|
// // Run the equivalent function for red
|
|
// bayer_gbrg8_to_bgr8_mhc(w, h, in, _out);
|
|
|
|
// // Now swap red and blue
|
|
// swapRedAndBlue(srcWidth * h, (Color3unorm8*)_out);
|
|
// }
|
|
|
|
// static void bayer_bggr8_to_bgr8_mhc(int w, int h,
|
|
// const unorm8* in, unorm8* _out) {
|
|
// // Run the equivalent function for red
|
|
// bayer_rggb8_to_bgr8_mhc(w, h, in, _out);
|
|
|
|
// // Now swap red and blue
|
|
// swapRedAndBlue(srcWidth * h, (Color3unorm8*)_out);
|
|
// }
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
} // namespace G3D
|