VideoCodec/Modules/Transform/ColourSpaceConverter.cpp
#include "ColourSpaceConverter.h"
namespace VideoCodec
{
ColourSpaceConverter::ColourSpaceConverter() : Module(COLOUR_SPACE_CONVERTER_MODULE_ID)
{
this->outputPlanes = false;
}
ColourSpaceConverter::~ColourSpaceConverter()
{
}
ConfigurationStatus ColourSpaceConverter::Configure(ConfigurationElement* configuration)
{
if (configuration != NULL && (configuration->GetValue("outputPlanes") != NULL) && *(configuration->GetValue("outputPlanes")->GetString()) == string("true"))
this->outputPlanes = true;
return MODULE_CONFIGURATION_OK;
}
void ColourSpaceConverter::ConvertRGBToYUVRepresentation(PictureInfo* picture, Codec* codec)
{
if (picture->GetColourFormat() != COLOUR_FORMAT_RGB)
Logger::LogMessage("Warning: Non-RGB colour format input received for conversion RGB to YUV.");
if (picture->GetPixelLayout() != PIXEL_LAYOUT_SCAN)
Logger::LogMessage("Warning: Scan order pixel data is required for colour space conversion.");
UnsignedByte* componentData = picture->GetUnsignedByteData();
PixelCount imageWidth = picture->GetPixelsX();
PixelCount imageHeight = picture->GetPixelsY();
// Use fixed point approximation.
int r, g, b;
for (int y = 0, index = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++, index += 3)
{
r = (int)componentData[index];
g = (int)componentData[index + 1];
b = (int)componentData[index + 2];
componentData[index] = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
componentData[index + 1] = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
componentData[index + 2] = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
}
}
// The component values have been converted in place.
picture->SetColourFormat(COLOUR_FORMAT_YUV);
// Outputs colour planes for this image for Y, U and V components. (Or more precisely, Y, Cb and Cr planes.)
if (this->outputPlanes)
{
// Set the other two components to include only one plane for each.
PictureInfo* yPicture = picture->Clone();
PictureInfo* cbPicture = picture->Clone();
PictureInfo* crPicture = picture->Clone();
UnsignedByte* yPictureComponents = yPicture->GetUnsignedByteData();
UnsignedByte* cbPictureComponents = cbPicture->GetUnsignedByteData();
UnsignedByte* crPictureComponents = crPicture->GetUnsignedByteData();
for (int index = 0; index < imageWidth * imageHeight * 3; index += 3)
{
yPictureComponents[index + 1] = yPictureComponents[index + 2] = 128;
cbPictureComponents[index] = 128;
cbPictureComponents[index + 2] = 128;
crPictureComponents[index] = 128;
crPictureComponents[index + 1] = 128;
}
// Move them back to RGB.
this->ConvertYUVToRGBRepresentation(yPicture);
this->ConvertYUVToRGBRepresentation(cbPicture);
this->ConvertYUVToRGBRepresentation(crPicture);
// Output the planes.
((FrameOutputModule*)codec->GetModule(FRAME_OUTPUT_MODULE_ID))->WriteImage(yPicture, "yPlane.png");
((FrameOutputModule*)codec->GetModule(FRAME_OUTPUT_MODULE_ID))->WriteImage(cbPicture, "cbPlane.png");
((FrameOutputModule*)codec->GetModule(FRAME_OUTPUT_MODULE_ID))->WriteImage(crPicture, "crPlane.png");
// Clean up.
delete yPicture;
delete cbPicture;
delete crPicture;
}
}
void ColourSpaceConverter::ConvertYUVToRGBRepresentation(PictureInfo* picture)
{
if (picture->GetColourFormat() != COLOUR_FORMAT_YUV)
Logger::LogMessage("Warning: Non-YUV colour format input received for conversion YUV to RGB.");
if (picture->GetPixelLayout() != PIXEL_LAYOUT_SCAN)
Logger::LogMessage("Warning: Scan order pixel data is required for colour space conversion.");
UnsignedByte* componentData = picture->GetUnsignedByteData();
int imageWidth = picture->GetPixelsX();
int imageHeight = picture->GetPixelsY();
// Use fixed point approximation.
int c, d, e;
for (int y = 0, index = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++, index += 3)
{
c = (int)componentData[index] - 16;
d = (int)componentData[index + 1] - 128;
e = (int)componentData[index + 2] - 128;
componentData[index] = colourClip(( 298 * c + 409 * e + 128) >> 8);
componentData[index + 1] = colourClip(( 298 * c - 100 * d - 208 * e + 128) >> 8);
componentData[index + 2] = colourClip(( 298 * c + 516 * d + 128) >> 8);
}
}
picture->SetColourFormat(COLOUR_FORMAT_RGB);
}
inline unsigned char ColourSpaceConverter::colourClip(int value)
{
return value > 255 ? (unsigned char)255 :
value < 0 ? (unsigned char)0 : value;
}
}