Add facility to read frames in RGB & RGBA format
[imageviewer.git] / colourSpace.cpp
blob4661310522c380bb5523e26ee4eea49bff594ea2
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id$
5 * The MIT License
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
25 * THE SOFTWARE.
27 * ***** END LICENSE BLOCK ***** */
29 #include "colourSpace.h"
30 #include "rawFrame.h"
32 #include <math.h>
33 #include <stdio.h>
35 #define DEBUG 0
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)
45 //Y row
46 matrix.a = Kr; //R column
47 matrix.b = Kg; //G
48 matrix.c = Kb; //B
50 // cb row
51 matrix.d = -1.0 * (Kr/(2.0*(1.0-Kb)));
52 matrix.e = -1.0 * (Kg/(2.0*(1.0-Kb)));
53 matrix.f = 0.5;
55 //cr row
56 matrix.g = 0.5;
57 matrix.h = -1.0 * (Kg/(2.0*(1.0-Kr)));
58 matrix.i = -1.0 * (Kb/(2.0*(1.0-Kr)));
60 if (DEBUG) {
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);
65 printf("\n");
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)
73 //R row
74 matrix.a = 1.0; //Y column
75 matrix.b = 0.0; //Cb
76 matrix.c = 2.0 * (1-Kr); //Cr
78 //G row
79 matrix.d = 1.0;
80 matrix.e = -1.0 * ( (2.0*(1.0-Kb)*Kb)/Kg );
81 matrix.f = -1.0 * ( (2.0*(1.0-Kr)*Kr)/Kg );
83 //B row
84 matrix.g = 1.0;
85 matrix.h = 2.0 * (1.0-Kb);
86 matrix.i = 0.0;
88 if (DEBUG) {
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);
93 printf("\n");
97 const RawFrame& ColourSpace::process(const RawFrame &src,
98 const MatrixType type,
99 const bool scaledRGB, const bool YOnly,
100 const int depth)
102 process_ext(src, _converted, type, scaledRGB, YOnly, depth);
103 return _converted;
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
151 + 0.5));
152 intMatrix.b = (int)(floor(matrix.b * intScaling * YUVCscale * RGBYscale
153 + 0.5));
154 intMatrix.c = (int)(floor(matrix.c * intScaling * YUVCscale * RGBYscale
155 + 0.5));
156 intMatrix.d = (int)(floor(matrix.d * intScaling * YUVYscale * RGBCscale
157 + 0.5));
158 intMatrix.e = (int)(floor(matrix.e * intScaling * YUVCscale * RGBCscale
159 + 0.5));
160 intMatrix.f = (int)(floor(matrix.f * intScaling * YUVCscale * RGBCscale
161 + 0.5));
162 intMatrix.g = (int)(floor(matrix.g * intScaling * YUVYscale * RGBCscale
163 + 0.5));
164 intMatrix.h = (int)(floor(matrix.h * intScaling * YUVCscale * RGBCscale
165 + 0.5));
166 intMatrix.i = (int)(floor(matrix.i * intScaling * YUVCscale * RGBCscale
167 + 0.5));
169 if (DEBUG) {
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);
174 printf("\n");
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) {
181 //source data is YUV
182 int Y = src.luma[line][x] - Yoffset;
183 int U = src.cb[line][x];
184 int V = src.cr[line][x];
186 if (YOnly == true) {
187 U = 0;
188 V = 0;
190 else {
191 U -= Coffset;
192 V -= Coffset;
195 //apply the matrix
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);
203 //Clip and store
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);
208 else {
209 //source data is RGB
210 int R = src.r[line][x];
211 int G = src.g[line][x];
212 int B = src.b[line][x];
214 //apply the matrix
215 int Y = ((intMatrix.a*R + intMatrix.b*G + intMatrix.c*B
216 + rounding) >> limit_depth) + Yoffset;
217 int U = Coffset;
218 int V = Coffset;
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);
227 //Clip and store
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);