summaryrefslogtreecommitdiff
path: root/test/rgb_xyz_test.cc
blob: b33a0f4ac30106adb3b73a1d96b2c31cc10303de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "image.h"
#include "rgb_xyz.h"
#include "xyz_frame.h"
#include "colour_conversion.h"
#include <boost/test/unit_test.hpp>

using std::max;
using boost::shared_ptr;

class SimpleImage : public dcp::Image
{
public:
	SimpleImage (dcp::Size size)
		: Image (size)
	{
		/* 48bpp */
		_stride[0] = _size.width * 6;
		_data[0] = new uint16_t[size.height * stride()[0] / 2];
	}

	~SimpleImage ()
	{
		delete[] _data[0];
	}

	uint16_t * const * data () const {
		return _data;
	}

	int const * stride () const {
		return _stride;
	}

private:
	uint16_t* _data[1];
	int _stride[1];
};

/** Convert a test image from sRGB to XYZ and check that the transforms are right */
BOOST_AUTO_TEST_CASE (rgb_xyz_test)
{
	unsigned int seed = 0;
	dcp::Size const size (640, 480);

	shared_ptr<const dcp::Image> rgb (new SimpleImage (size));
	for (int y = 0; y < size.height; ++y) {
		uint16_t* p = rgb->data()[0] + y * rgb->stride()[0] / 2;
		for (int x = 0; x < size.width; ++x) {
			/* Write a 12-bit random number for each component */
			for (int c = 0; c < 3; ++c) {
				*p = (rand_r (&seed) & 0xfff) << 4;
				++p;
			}
		}
	}

	shared_ptr<dcp::XYZFrame> xyz = dcp::rgb_to_xyz (rgb, dcp::ColourConversion::srgb_to_xyz);

	for (int y = 0; y < size.height; ++y) {
		uint16_t* p = rgb->data()[0] + y * rgb->stride()[0] / 2;
		for (int x = 0; x < size.width; ++x) {

			double cr = *p++ / 65535.0;
			double cg = *p++ / 65535.0;
			double cb = *p++ / 65535.0;

			/* Input gamma */

			if (cr < 0.04045) {
				cr /= 12.92;
			} else {
				cr = pow ((cr + 0.055) / 1.055, 2.4);
			}

			if (cg < 0.04045) {
				cg /= 12.92;
			} else {
				cg = pow ((cg + 0.055) / 1.055, 2.4);
			}

			if (cb < 0.04045) {
				cb /= 12.92;
			} else {
				cb = pow ((cb + 0.055) / 1.055, 2.4);
			}

			/* Matrix */

			double cx = cr * 0.4124564 + cg * 0.3575761 + cb * 0.1804375;
			double cy = cr * 0.2126729 + cg * 0.7151522 + cb * 0.0721750;
			double cz = cr * 0.0193339 + cg * 0.1191920 + cb * 0.9503041;

			/* Compand */

			cx *= 48 / 52.37;
			cy *= 48 / 52.37;
			cz *= 48 / 52.37;

			/* Output gamma */

			cx = pow (cx, 1 / 2.6);
			cy = pow (cy, 1 / 2.6);
			cz = pow (cz, 1 / 2.6);

			BOOST_REQUIRE_CLOSE (cx * 4095, xyz->data(0)[y * size.width + x], 1);
			BOOST_REQUIRE_CLOSE (cy * 4095, xyz->data(1)[y * size.width + x], 1);
			BOOST_REQUIRE_CLOSE (cz * 4095, xyz->data(2)[y * size.width + x], 1);
		}
	}
}