diff options
| author | Carl Hetherington <cth@carlh.net> | 2015-01-03 21:33:30 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2015-01-03 21:33:30 +0000 |
| commit | 9655ed4740f08899698052f232256fcf7b77c58e (patch) | |
| tree | 195e8f30ec4c5dd5beeecfb371acf7a3ceaa7898 /src | |
| parent | 986bb0acba0aa73fc2ac0190a32e8fa8c6e636b4 (diff) | |
Various fixes to XYZ/RGB transforms.
Diffstat (limited to 'src')
| -rw-r--r-- | src/colour_conversion.cc | 15 | ||||
| -rw-r--r-- | src/colour_conversion.h | 2 | ||||
| -rw-r--r-- | src/gamma_transfer_function.cc | 18 | ||||
| -rw-r--r-- | src/gamma_transfer_function.h | 10 | ||||
| -rw-r--r-- | src/image.h | 5 | ||||
| -rw-r--r-- | src/modified_gamma_transfer_function.cc | 39 | ||||
| -rw-r--r-- | src/modified_gamma_transfer_function.h | 22 | ||||
| -rw-r--r-- | src/mono_picture_frame.cc | 6 | ||||
| -rw-r--r-- | src/mono_picture_frame.h | 2 | ||||
| -rw-r--r-- | src/rgb_xyz.cc | 59 | ||||
| -rw-r--r-- | src/rgb_xyz.h | 2 | ||||
| -rw-r--r-- | src/stereo_picture_frame.cc | 6 | ||||
| -rw-r--r-- | src/stereo_picture_frame.h | 2 | ||||
| -rw-r--r-- | src/transfer_function.cc | 19 | ||||
| -rw-r--r-- | src/transfer_function.h | 13 | ||||
| -rw-r--r-- | src/xyz_frame.cc | 2 |
16 files changed, 130 insertions, 92 deletions
diff --git a/src/colour_conversion.cc b/src/colour_conversion.cc index 28edf9bc..f2e85e76 100644 --- a/src/colour_conversion.cc +++ b/src/colour_conversion.cc @@ -26,22 +26,21 @@ using boost::shared_ptr; using namespace dcp; ColourConversion ColourConversion::srgb_to_xyz ( - shared_ptr<const TransferFunction> (new ModifiedGammaTransferFunction (2.4, 0.04045, 0.055, 12.92)), + shared_ptr<const TransferFunction> (new ModifiedGammaTransferFunction (false, 2.4, 0.04045, 0.055, 12.92)), dcp::colour_matrix::srgb_to_xyz, - shared_ptr<const TransferFunction> (new GammaTransferFunction (2.6)) + shared_ptr<const TransferFunction> (new GammaTransferFunction (true, 2.6)) ); -/* XXX: what sort of RGB is this...? */ -ColourConversion ColourConversion::xyz_to_rgb ( - shared_ptr<const TransferFunction> (new GammaTransferFunction (2.6)), +ColourConversion ColourConversion::xyz_to_srgb ( + shared_ptr<const TransferFunction> (new GammaTransferFunction (false, 2.6)), dcp::colour_matrix::xyz_to_rgb, - shared_ptr<const TransferFunction> (new GammaTransferFunction (2.2)) + shared_ptr<const TransferFunction> (new ModifiedGammaTransferFunction (true, 2.4, 0.04045, 0.055, 12.92)) ); ColourConversion ColourConversion::rec709_to_xyz ( - shared_ptr<const TransferFunction> (new ModifiedGammaTransferFunction (2.4, 0.081, 0.099, 4.5)), + shared_ptr<const TransferFunction> (new ModifiedGammaTransferFunction (false, 2.4, 0.081, 0.099, 4.5)), dcp::colour_matrix::srgb_to_xyz, - shared_ptr<const TransferFunction> (new GammaTransferFunction (2.6)) + shared_ptr<const TransferFunction> (new GammaTransferFunction (true, 2.6)) ); ColourConversion::ColourConversion ( diff --git a/src/colour_conversion.h b/src/colour_conversion.h index 9bb7c6ee..e2a8c6bc 100644 --- a/src/colour_conversion.h +++ b/src/colour_conversion.h @@ -64,7 +64,7 @@ public: bool about_equal (ColourConversion const & other, float epsilon) const; static ColourConversion srgb_to_xyz; - static ColourConversion xyz_to_rgb; + static ColourConversion xyz_to_srgb; static ColourConversion rec709_to_xyz; protected: diff --git a/src/gamma_transfer_function.cc b/src/gamma_transfer_function.cc index b4aa20f1..9d5ceba4 100644 --- a/src/gamma_transfer_function.cc +++ b/src/gamma_transfer_function.cc @@ -25,27 +25,33 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; using namespace dcp; -GammaTransferFunction::GammaTransferFunction (float gamma) - : _gamma (gamma) +GammaTransferFunction::GammaTransferFunction (bool inverse, double gamma) + : TransferFunction (inverse) + , _gamma (gamma) { } -float * +double * GammaTransferFunction::make_lut (int bit_depth) const { int const bit_length = pow (2, bit_depth); - float* lut = new float[int(std::pow(2.0f, bit_depth))]; + double* lut = new double[int(std::pow(2.0f, bit_depth))]; + double const gamma = _inverse ? (1 / _gamma) : _gamma; for (int i = 0; i < bit_length; ++i) { - lut[i] = pow(float(i) / (bit_length - 1), _gamma); + lut[i] = pow(double(i) / (bit_length - 1), gamma); } return lut; } bool -GammaTransferFunction::about_equal (shared_ptr<const TransferFunction> other, float epsilon) const +GammaTransferFunction::about_equal (shared_ptr<const TransferFunction> other, double epsilon) const { + if (!TransferFunction::about_equal (other, epsilon)) { + return false; + } + shared_ptr<const GammaTransferFunction> o = dynamic_pointer_cast<const GammaTransferFunction> (other); if (!o) { return false; diff --git a/src/gamma_transfer_function.h b/src/gamma_transfer_function.h index 85035f66..17efe12e 100644 --- a/src/gamma_transfer_function.h +++ b/src/gamma_transfer_function.h @@ -24,19 +24,19 @@ namespace dcp { class GammaTransferFunction : public TransferFunction { public: - GammaTransferFunction (float gamma); + GammaTransferFunction (bool inverse, double gamma); - float gamma () const { + double gamma () const { return _gamma; } - bool about_equal (boost::shared_ptr<const TransferFunction> other, float epsilon) const; + bool about_equal (boost::shared_ptr<const TransferFunction> other, double epsilon) const; protected: - float * make_lut (int bit_depth) const; + double * make_lut (int bit_depth) const; private: - float _gamma; + double _gamma; }; } diff --git a/src/image.h b/src/image.h index 941325cd..abc040d4 100644 --- a/src/image.h +++ b/src/image.h @@ -29,8 +29,9 @@ public: Image (boost::shared_ptr<const Image>); virtual ~Image () {} - virtual uint8_t** data () const = 0; - virtual int* stride () const = 0; + virtual uint16_t * const * data () const = 0; + /** @return array of strides in bytes */ + virtual int const * stride () const = 0; Size size () const { return _size; diff --git a/src/modified_gamma_transfer_function.cc b/src/modified_gamma_transfer_function.cc index 7878773b..ef4bb225 100644 --- a/src/modified_gamma_transfer_function.cc +++ b/src/modified_gamma_transfer_function.cc @@ -25,8 +25,9 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; using namespace dcp; -ModifiedGammaTransferFunction::ModifiedGammaTransferFunction (float power, float threshold, float A, float B) - : _power (power) +ModifiedGammaTransferFunction::ModifiedGammaTransferFunction (bool inverse, double power, double threshold, double A, double B) + : TransferFunction (inverse) + , _power (power) , _threshold (threshold) , _A (A) , _B (B) @@ -34,17 +35,29 @@ ModifiedGammaTransferFunction::ModifiedGammaTransferFunction (float power, float } -float * +double * ModifiedGammaTransferFunction::make_lut (int bit_depth) const { int const bit_length = pow (2, bit_depth); - float* lut = new float[int(std::pow(2.0f, bit_depth))]; - for (int i = 0; i < bit_length; ++i) { - float const p = static_cast<float> (i) / (bit_length - 1); - if (p > _threshold) { - lut[i] = pow ((p + _A) / (1 + _A), _power); - } else { - lut[i] = p / _B; + double* lut = new double[int(std::pow(2.0f, bit_depth))]; + if (_inverse) { + double const threshold = _threshold / _B; + for (int i = 0; i < bit_length; ++i) { + double const p = static_cast<double> (i) / (bit_length - 1); + if (p > threshold) { + lut[i] = (1 + _A) * pow (p, 1 / _power) - _A; + } else { + lut[i] = p * _B; + } + } + } else { + for (int i = 0; i < bit_length; ++i) { + double const p = static_cast<double> (i) / (bit_length - 1); + if (p > _threshold) { + lut[i] = pow ((p + _A) / (1 + _A), _power); + } else { + lut[i] = p / _B; + } } } @@ -52,8 +65,12 @@ ModifiedGammaTransferFunction::make_lut (int bit_depth) const } bool -ModifiedGammaTransferFunction::about_equal (shared_ptr<const TransferFunction> other, float epsilon) const +ModifiedGammaTransferFunction::about_equal (shared_ptr<const TransferFunction> other, double epsilon) const { + if (!TransferFunction::about_equal (other, epsilon)) { + return false; + } + shared_ptr<const ModifiedGammaTransferFunction> o = dynamic_pointer_cast<const ModifiedGammaTransferFunction> (other); if (!o) { return false; diff --git a/src/modified_gamma_transfer_function.h b/src/modified_gamma_transfer_function.h index 0c6a6b84..aec52de7 100644 --- a/src/modified_gamma_transfer_function.h +++ b/src/modified_gamma_transfer_function.h @@ -29,34 +29,34 @@ namespace dcp { class ModifiedGammaTransferFunction : public TransferFunction { public: - ModifiedGammaTransferFunction (float power, float threshold, float A, float B); + ModifiedGammaTransferFunction (bool inverse, double power, double threshold, double A, double B); - float power () const { + double power () const { return _power; } - float threshold () const { + double threshold () const { return _threshold; } - float A () const { + double A () const { return _A; } - float B () const { + double B () const { return _B; } - bool about_equal (boost::shared_ptr<const TransferFunction>, float epsilon) const; + bool about_equal (boost::shared_ptr<const TransferFunction>, double epsilon) const; protected: - float * make_lut (int bit_depth) const; + double * make_lut (int bit_depth) const; private: - float _power; - float _threshold; - float _A; - float _B; + double _power; + double _threshold; + double _A; + double _B; }; } diff --git a/src/mono_picture_frame.cc b/src/mono_picture_frame.cc index 31499c64..4fe9356c 100644 --- a/src/mono_picture_frame.cc +++ b/src/mono_picture_frame.cc @@ -123,16 +123,16 @@ MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const { return xyz_to_rgba ( decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce), - ColourConversion::xyz_to_rgb + ColourConversion::xyz_to_srgb ); } void -MonoPictureFrame::rgb_frame (uint8_t* buffer) const +MonoPictureFrame::rgb_frame (uint16_t* buffer) const { xyz_to_rgb ( decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), 0), - ColourConversion::xyz_to_rgb, + ColourConversion::xyz_to_srgb, buffer ); } diff --git a/src/mono_picture_frame.h b/src/mono_picture_frame.h index 78728fbf..50ea0891 100644 --- a/src/mono_picture_frame.h +++ b/src/mono_picture_frame.h @@ -51,7 +51,7 @@ public: ~MonoPictureFrame (); boost::shared_ptr<ARGBFrame> argb_frame (int reduce = 0, float srgb_gamma = 2.4) const; - void rgb_frame (uint8_t* buffer) const; + void rgb_frame (uint16_t* buffer) const; uint8_t const * j2k_data () const; uint8_t* j2k_data (); int j2k_size () const; diff --git a/src/rgb_xyz.cc b/src/rgb_xyz.cc index 35332fc2..faddf013 100644 --- a/src/rgb_xyz.cc +++ b/src/rgb_xyz.cc @@ -61,8 +61,8 @@ dcp::xyz_to_rgba ( shared_ptr<ARGBFrame> argb_frame (new ARGBFrame (xyz_frame->size ())); uint8_t* argb = argb_frame->data (); - float const * lut_in = conversion.in()->lut (16); - float const * lut_out = conversion.out()->lut (12); + double const * lut_in = conversion.in()->lut (16); + double const * lut_out = conversion.out()->lut (12); boost::numeric::ublas::matrix<double> matrix = conversion.matrix (); for (int y = 0; y < xyz_frame->size().height; ++y) { @@ -96,9 +96,9 @@ dcp::xyz_to_rgba ( d.b = max (d.b, 0.0); /* Out gamma LUT */ - *argb_line++ = lut_out[(int) (d.b * max_colour)] * 0xff; - *argb_line++ = lut_out[(int) (d.g * max_colour)] * 0xff; - *argb_line++ = lut_out[(int) (d.r * max_colour)] * 0xff; + *argb_line++ = lut_out[int(rint(d.b * max_colour))] * 0xff; + *argb_line++ = lut_out[int(rint(d.g * max_colour))] * 0xff; + *argb_line++ = lut_out[int(rint(d.r * max_colour))] * 0xff; *argb_line++ = 0xff; } @@ -110,21 +110,18 @@ dcp::xyz_to_rgba ( /** Convert an openjpeg XYZ image to RGB. * @param xyz_frame Frame in XYZ. - * @param lut_in Input Gamma LUT to use. - * @param lut_out Output Gamma LUT to use. - * @param buffer Buffer to write RGB data to; will be written - * as one byte R, one byte G, one byte B, one byte R etc. with - * no padding at line ends. + * @param conversion Colour conversion to use. + * @param buffer Buffer to write RGB data to; rgb will be packed RGB + * 16:16:16, 48bpp, 16R, 16G, 16B, with the 2-byte value for each + * R/G/B component stored as little-endian; i.e. AV_PIX_FMT_RGB48LE. */ void dcp::xyz_to_rgb ( boost::shared_ptr<const XYZFrame> xyz_frame, ColourConversion const & conversion, - uint8_t* buffer + uint16_t* buffer ) { - int const max_colour = pow (2, 12) - 1; - struct { double x, y, z; } s; @@ -132,21 +129,22 @@ dcp::xyz_to_rgb ( struct { double r, g, b; } d; - + + /* These should be 12-bit values from 0-4095 */ int* xyz_x = xyz_frame->data (0); int* xyz_y = xyz_frame->data (1); int* xyz_z = xyz_frame->data (2); - float const * lut_in = conversion.in()->lut (16); - float const * lut_out = conversion.out()->lut (12); + double const * lut_in = conversion.in()->lut (12); + double const * lut_out = conversion.out()->lut (16); boost::numeric::ublas::matrix<double> matrix = conversion.matrix (); for (int y = 0; y < xyz_frame->size().height; ++y) { - uint8_t* buffer_line = buffer; + uint16_t* buffer_line = buffer; for (int x = 0; x < xyz_frame->size().width; ++x) { DCP_ASSERT (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_y < 4096 && *xyz_z < 4096); - + /* In gamma LUT */ s.x = lut_in[*xyz_x++]; s.y = lut_in[*xyz_y++]; @@ -170,11 +168,10 @@ dcp::xyz_to_rgb ( d.b = min (d.b, 1.0); d.b = max (d.b, 0.0); - - /* Out gamma LUT */ - *buffer_line++ = lut_out[(int) (d.r * max_colour)] * 0xff; - *buffer_line++ = lut_out[(int) (d.g * max_colour)] * 0xff; - *buffer_line++ = lut_out[(int) (d.b * max_colour)] * 0xff; + + *buffer_line++ = rint(lut_out[int(rint(d.r * 65535))] * 65535); + *buffer_line++ = rint(lut_out[int(rint(d.g * 65535))] * 65535); + *buffer_line++ = rint(lut_out[int(rint(d.b * 65535))] * 65535); } buffer += xyz_frame->size().width * 3; @@ -200,20 +197,20 @@ dcp::rgb_to_xyz ( double x, y, z; } d; - float const * lut_in = conversion.in()->lut (12); - float const * lut_out = conversion.out()->lut (16); + double const * lut_in = conversion.in()->lut (12); + double const * lut_out = conversion.out()->lut (16); boost::numeric::ublas::matrix<double> matrix = conversion.matrix (); int jn = 0; for (int y = 0; y < rgb->size().height; ++y) { - uint16_t* p = reinterpret_cast<uint16_t *> (rgb->data()[0] + y * rgb->stride()[0]); + uint16_t* p = rgb->data()[0] + y * rgb->stride()[0] / 2; for (int x = 0; x < rgb->size().width; ++x) { /* In gamma LUT (converting 16-bit to 12-bit) */ s.r = lut_in[*p++ >> 4]; s.g = lut_in[*p++ >> 4]; s.b = lut_in[*p++ >> 4]; - + /* RGB to XYZ Matrix */ d.x = ((s.r * matrix(0, 0)) + (s.g * matrix(0, 1)) + (s.b * matrix(0, 2))); d.y = ((s.r * matrix(1, 0)) + (s.g * matrix(1, 1)) + (s.b * matrix(1, 2))); @@ -229,9 +226,9 @@ dcp::rgb_to_xyz ( DCP_ASSERT (d.z >= 0 && d.z < 65536); /* Out gamma LUT */ - xyz->data(0)[jn] = lut_out[(int) d.x] * 4096; - xyz->data(1)[jn] = lut_out[(int) d.y] * 4096; - xyz->data(2)[jn] = lut_out[(int) d.z] * 4096; + xyz->data(0)[jn] = lut_out[int(rint(d.x))] * 4095; + xyz->data(1)[jn] = lut_out[int(rint(d.y))] * 4095; + xyz->data(2)[jn] = lut_out[int(rint(d.z))] * 4095; ++jn; } @@ -251,7 +248,7 @@ dcp::xyz_to_xyz (shared_ptr<const Image> xyz_16) int jn = 0; for (int y = 0; y < xyz_16->size().height; ++y) { - uint16_t* p = reinterpret_cast<uint16_t *> (xyz_16->data()[0] + y * xyz_16->stride()[0]); + uint16_t* p = xyz_16->data()[0] + y * xyz_16->stride()[0] / 2; for (int x = 0; x < xyz_16->size().width; ++x) { /* Truncate 16-bit to 12-bit */ xyz_12->data(0)[jn] = *p++ >> 4; diff --git a/src/rgb_xyz.h b/src/rgb_xyz.h index a6463b0d..4dd25b28 100644 --- a/src/rgb_xyz.h +++ b/src/rgb_xyz.h @@ -28,7 +28,7 @@ class Image; class ColourConversion; extern boost::shared_ptr<ARGBFrame> xyz_to_rgba (boost::shared_ptr<const XYZFrame>, ColourConversion const & conversion); -extern void xyz_to_rgb (boost::shared_ptr<const XYZFrame>, ColourConversion const & conversion, uint8_t* buffer); +extern void xyz_to_rgb (boost::shared_ptr<const XYZFrame>, ColourConversion const & conversion, uint16_t* buffer); extern boost::shared_ptr<XYZFrame> rgb_to_xyz (boost::shared_ptr<const Image>, ColourConversion const & conversion); extern boost::shared_ptr<XYZFrame> xyz_to_xyz (boost::shared_ptr<const Image>); diff --git a/src/stereo_picture_frame.cc b/src/stereo_picture_frame.cc index 7d989777..3e872e2b 100644 --- a/src/stereo_picture_frame.cc +++ b/src/stereo_picture_frame.cc @@ -89,11 +89,11 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const break; } - return xyz_to_rgba (xyz_frame, ColourConversion::xyz_to_rgb); + return xyz_to_rgba (xyz_frame, ColourConversion::xyz_to_srgb); } void -StereoPictureFrame::rgb_frame (Eye eye, uint8_t* buffer) const +StereoPictureFrame::rgb_frame (Eye eye, uint16_t* buffer) const { shared_ptr<XYZFrame> xyz_frame; switch (eye) { @@ -105,7 +105,7 @@ StereoPictureFrame::rgb_frame (Eye eye, uint8_t* buffer) const break; } - return xyz_to_rgb (xyz_frame, ColourConversion::xyz_to_rgb, buffer); + return xyz_to_rgb (xyz_frame, ColourConversion::xyz_to_srgb, buffer); } uint8_t const * diff --git a/src/stereo_picture_frame.h b/src/stereo_picture_frame.h index 578bb3de..e8ef689d 100644 --- a/src/stereo_picture_frame.h +++ b/src/stereo_picture_frame.h @@ -44,7 +44,7 @@ public: ~StereoPictureFrame (); boost::shared_ptr<ARGBFrame> argb_frame (Eye eye, int reduce = 0, float srgb_gamma = 2.4) const; - void rgb_frame (Eye eye, uint8_t* buffer) const; + void rgb_frame (Eye eye, uint16_t* buffer) const; uint8_t const * left_j2k_data () const; uint8_t* left_j2k_data (); int left_j2k_size () const; diff --git a/src/transfer_function.cc b/src/transfer_function.cc index 2c7e3e52..d889cbbc 100644 --- a/src/transfer_function.cc +++ b/src/transfer_function.cc @@ -22,21 +22,28 @@ using std::pow; using std::map; +using boost::shared_ptr; using namespace dcp; +TransferFunction::TransferFunction (bool inverse) + : _inverse (inverse) +{ + +} + TransferFunction::~TransferFunction () { - for (map<int, float*>::const_iterator i = _luts.begin(); i != _luts.end(); ++i) { + for (map<int, double*>::const_iterator i = _luts.begin(); i != _luts.end(); ++i) { delete[] i->second; } _luts.clear (); } -float const * +double const * TransferFunction::lut (int bit_depth) const { - map<int, float*>::const_iterator i = _luts.find (bit_depth); + map<int, double*>::const_iterator i = _luts.find (bit_depth); if (i != _luts.end ()) { return i->second; } @@ -44,3 +51,9 @@ TransferFunction::lut (int bit_depth) const _luts[bit_depth] = make_lut (bit_depth); return _luts[bit_depth]; } + +bool +TransferFunction::about_equal (shared_ptr<const TransferFunction> other, double) const +{ + return _inverse == other->_inverse; +} diff --git a/src/transfer_function.h b/src/transfer_function.h index 31a794e2..16d00c1a 100644 --- a/src/transfer_function.h +++ b/src/transfer_function.h @@ -29,17 +29,22 @@ namespace dcp { class TransferFunction : public boost::noncopyable { public: + TransferFunction (bool inverse); + virtual ~TransferFunction (); - float const * lut (int bit_depth) const; + /** @return A look-up table (of size 2^bit_depth) whose values range from 0 to 1 */ + double const * lut (int bit_depth) const; - virtual bool about_equal (boost::shared_ptr<const TransferFunction> other, float epsilon) const = 0; + virtual bool about_equal (boost::shared_ptr<const TransferFunction> other, double epsilon) const; protected: - virtual float * make_lut (int bit_depth) const = 0; + virtual double * make_lut (int bit_depth) const = 0; + + bool _inverse; private: - mutable std::map<int, float*> _luts; + mutable std::map<int, double*> _luts; }; } diff --git a/src/xyz_frame.cc b/src/xyz_frame.cc index 48098361..f1c69491 100644 --- a/src/xyz_frame.cc +++ b/src/xyz_frame.cc @@ -72,7 +72,7 @@ XYZFrame::~XYZFrame () } /** @param c Component index (0, 1 or 2) - * @return Pointer to the data for component c. + * @return Pointer to the data for component c; 12-bit values from 0-4095. */ int * XYZFrame::data (int c) const |
