1 /* ***** BEGIN LICENSE BLOCK *****
7 * Copyright (c) 2008 BBC Research
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * ***** END LICENSE BLOCK ***** */
29 #include "colourSpace.h"
37 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
38 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
39 #define CLIP(x,min,max) MAX(MIN(x,max),min)
41 //build a colour matrix to convert from RGB to YUV
42 void ColourSpace::buildYUVMatrix(ColourMatrix
&matrix
, const float Kr
,
43 const float Kg
, const float Kb
)
46 matrix
.a
= Kr
; //R column
51 matrix
.d
= -1.0 * (Kr
/(2.0*(1.0-Kb
)));
52 matrix
.e
= -1.0 * (Kg
/(2.0*(1.0-Kb
)));
57 matrix
.h
= -1.0 * (Kg
/(2.0*(1.0-Kr
)));
58 matrix
.i
= -1.0 * (Kb
/(2.0*(1.0-Kr
)));
61 printf("Building YUV->RGB matrix with Kr=%f Kg=%f, Kb=%f\n", Kr
, Kg
, Kb
);
62 printf("%f %f %f\n", matrix
.a
, matrix
.b
, matrix
.c
);
63 printf("%f %f %f\n", matrix
.d
, matrix
.e
, matrix
.f
);
64 printf("%f %f %f\n", matrix
.g
, matrix
.h
, matrix
.i
);
69 //build a colour matrix to convert from YUV to RGB
70 void ColourSpace::buildRGBMatrix(ColourMatrix
&matrix
, const float Kr
,
71 const float Kg
, const float Kb
)
74 matrix
.a
= 1.0; //Y column
76 matrix
.c
= 2.0 * (1-Kr
); //Cr
80 matrix
.e
= -1.0 * ( (2.0*(1.0-Kb
)*Kb
)/Kg
);
81 matrix
.f
= -1.0 * ( (2.0*(1.0-Kr
)*Kr
)/Kg
);
85 matrix
.h
= 2.0 * (1.0-Kb
);
89 printf("Building YUV->RGB matrix with Kr=%f Kg=%f, Kb=%f\n", Kr
, Kg
, Kb
);
90 printf("%f %f %f\n", matrix
.a
, matrix
.b
, matrix
.c
);
91 printf("%f %f %f\n", matrix
.d
, matrix
.e
, matrix
.f
);
92 printf("%f %f %f\n", matrix
.g
, matrix
.h
, matrix
.i
);
97 const RawFrame
& ColourSpace::process(const RawFrame
&src
,
98 const MatrixType type
,
99 const bool scaledRGB
, const bool YOnly
,
102 process_ext(src
, _converted
, type
, scaledRGB
, YOnly
, depth
);
106 //using a particular colour matrix, convert YUV->RGB or RGB->YUV
107 //the YUV data is assumed to have 'video' levels, with black at 16 for 8 bit pictures
108 //RGB data can be scaled (0-255) or unscaled (16-235) with respect to the YUV
109 void ColourSpace::process_ext(const RawFrame
&src
, RawFrame
&dest
,
110 const MatrixType type
, const bool scaledRGB
,
111 const bool YOnly
, const int depth
)
113 //we only deal with YUV444 or RGB sources
114 assert(src
.chroma
== RawFrame::Cr444
|| src
.chroma
== RawFrame::CrRGB
);
116 const int maxVal
= (1 << depth
) - 1; //clip level for results
117 const int Yoffset
= scaledRGB
? 1 << (4 + (depth
-8)) : 0; //Y black level
118 const int Coffset
= 1 << (7 + (depth
-8)); //C mid-point
121 const int limit_depth
= (depth
> 14) ? 14 : depth
;
122 const double intScaling
= (float)(1 << (8 + (limit_depth
-8))); //scale floating point colour matrix to integer
123 const int rounding
= 1 << (7 + (limit_depth
-8)); //scaled 0.5
125 //scaling factors for when converting from YUV to RGB
126 double YUVYscale
= 1.0; //applied to column 1 of the YUV->RGB matrix
127 double YUVCscale
= 1.0; //applied to column 2&3 of the YUV->RGB matrix
129 //scaling factors for when converting from RGB to YUV
130 double RGBYscale
= 1.0; //applied to row 1 of the RGB->YUV matrix
131 double RGBCscale
= 1.0; //applied to row 2&3 of the RGB->YUV matrix
133 if ((type
== SDTVtoRGB
|| type
== HDTVtoRGB
) && scaledRGB
== true) {
134 //scale up to 0-255 RGB values from video levels
135 YUVYscale
= 255.0/219.0;
136 YUVCscale
= 255.0/224.0;
139 if ((type
== SDTVtoYUV
|| type
== HDTVtoYUV
) && scaledRGB
== true) {
140 //scale 0-255 RGB values down to video levels
141 RGBYscale
= 219.0/255.0;
142 RGBCscale
= 224.0/255.0;
145 //select the required matrix
146 ColourMatrix
& matrix
= matrices
[type
];
148 //scale the matrix as necessary and convert to integers
149 ColourMatrixInt intMatrix
;
150 intMatrix
.a
= (int)(floor(matrix
.a
* intScaling
* YUVYscale
* RGBYscale
152 intMatrix
.b
= (int)(floor(matrix
.b
* intScaling
* YUVCscale
* RGBYscale
154 intMatrix
.c
= (int)(floor(matrix
.c
* intScaling
* YUVCscale
* RGBYscale
156 intMatrix
.d
= (int)(floor(matrix
.d
* intScaling
* YUVYscale
* RGBCscale
158 intMatrix
.e
= (int)(floor(matrix
.e
* intScaling
* YUVCscale
* RGBCscale
160 intMatrix
.f
= (int)(floor(matrix
.f
* intScaling
* YUVCscale
* RGBCscale
162 intMatrix
.g
= (int)(floor(matrix
.g
* intScaling
* YUVYscale
* RGBCscale
164 intMatrix
.h
= (int)(floor(matrix
.h
* intScaling
* YUVCscale
* RGBCscale
166 intMatrix
.i
= (int)(floor(matrix
.i
* intScaling
* YUVCscale
* RGBCscale
170 printf("Using integer matrix :\n");
171 printf("%4d %4d %4d\n", intMatrix
.a
, intMatrix
.b
, intMatrix
.c
);
172 printf("%4d %4d %4d\n", intMatrix
.d
, intMatrix
.e
, intMatrix
.f
);
173 printf("%4d %4d %4d\n", intMatrix
.g
, intMatrix
.h
, intMatrix
.i
);
177 for (int line
=0; line
<src
.luma
.height(); line
++) {
178 for (int x
=0; x
<src
.luma
.width(); x
++) {
180 if (src
.chroma
== RawFrame::Cr444
) {
182 int Y
= src
.luma
[line
][x
] - Yoffset
;
183 int U
= src
.cb
[line
][x
];
184 int V
= src
.cr
[line
][x
];
196 int R
= ((intMatrix
.a
*Y
+ intMatrix
.b
*U
+ intMatrix
.c
*V
197 + rounding
) >> limit_depth
);
198 int G
= ((intMatrix
.d
*Y
+ intMatrix
.e
*U
+ intMatrix
.f
*V
199 + rounding
) >> limit_depth
);
200 int B
= ((intMatrix
.g
*Y
+ intMatrix
.h
*U
+ intMatrix
.i
*V
201 + rounding
) >> limit_depth
);
204 dest
.r
[line
][x
] = CLIP(R
, 0, maxVal
);
205 dest
.g
[line
][x
] = CLIP(G
, 0, maxVal
);
206 dest
.b
[line
][x
] = CLIP(B
, 0, maxVal
);
210 int R
= src
.r
[line
][x
];
211 int G
= src
.g
[line
][x
];
212 int B
= src
.b
[line
][x
];
215 int Y
= ((intMatrix
.a
*R
+ intMatrix
.b
*G
+ intMatrix
.c
*B
216 + rounding
) >> limit_depth
) + Yoffset
;
220 if (YOnly
== false) {
221 U
+= ((intMatrix
.d
*R
+ intMatrix
.e
*G
+ intMatrix
.f
*B
222 + rounding
) >> limit_depth
);
223 V
+= ((intMatrix
.g
*R
+ intMatrix
.h
*G
+ intMatrix
.i
*B
224 + rounding
) >> limit_depth
);
228 dest
.luma
[line
][x
]= CLIP(Y
, 0, maxVal
);
229 dest
.cb
[line
][x
] = CLIP(U
, 0, maxVal
);
230 dest
.cr
[line
][x
] = CLIP(V
, 0, maxVal
);