# YCbCr to jpeg-YCbCr

Im sampling an image in YCbCr from an ov7670 camera and using jpegant library to encode a jpeg file. Whenever I do it directly using Y,Cb,Cr values from my camera, I get a pink-violet version of the image. As far as I can understand on Wikipedia, there are different YCbCr standards, so I guess my camera use a different YCbCr standard.

Since the Jpegant library comes with an RGB example, if I convert my YCbCr values to RGB and then again rgb to YCbCr (an then JPEG) through the provided example, I get the a decent result.

Is there any way to get jpeg-YCbCr from my camera YCbCr (or any other YCbCr standard)?

EDIT:

• The camera sends me YCbCr in 4:2:2 format (that means that two sequential pixel share the same Cb and Cr channels), I proceed to downsample them to 4:2:0 ;

• Encode those samples into jpeg and get a pink-violet image ;

• I convert camera YCbCr to RGB this way :

.

R = Y + 1.402 * (Cr - 128)

G = Y + 1.772 * (Cb - 128)

B = Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr- 128)


Those values are good, I checked. I then convert them back into YCbCr using the formula provided with the library example:

Y' = 0.299*R + 0.587*G + 0.114*B

Cb' = -0.1687*R - 0.3313*G + 0.5*B + 128

Cr' = 0.5*R - 0.4187*G - 0.0813*B + 128


With new values, it encodes correctly .

Example YCbCr of values :

before:

156 144 145

after:

177 105 129

• Can you clarify the process: 1-The camera sends you YCbCr samples according to some standard you don't know, 2- When you use those samples and encode them into JPEG using jpegant the result is pink-violet dominated. 3-[unclear part] you convert camera YCbCr to RGB (how?) then RGB back to YCbCr (how?) and apply jpegant this time you get normal result? Please clarify these steps. – Fat32 Jul 28 '17 at 23:22
• Added in the post – Eraclea Jul 28 '17 at 23:52
• ok. But then you solved your problem. After you apply the two matrix multiplications to your YCbCr samples, it is converted to proper YcbCr values? It means you found the camera scaling. Why don't you just apply those two conversions on camera outputs to convert them into proper YCbCr values? – Fat32 Jul 29 '17 at 0:43
• I forgot to say that after YCbCr to RGB you have to clamp values between 0 and 255 because they usually gets higher. You are right, on a desktop pc it works fine, but im doing it on a microcontroller and this way it takes about 2-3 times the original conversion time. Plus, wikipedia says that the first transform is supposed to be the inverse of the second one, but that's not so true as you can see it gives me back different results. Here, at jpeg conversion: en.wikipedia.org/wiki/YCbCr – Eraclea Jul 29 '17 at 2:41
• You can convert that transformation into single forward transform which requires 5 MUL + 7 ADD + MOV's per pixel (YCbCr) is that too much for your micro processor? The multiplications are floating point but you can get an approximate integer multiplication with shifts if exact precision is not a constraint. – Fat32 Jul 29 '17 at 13:02

The matrix that will convert your camera provided YCbCr samples to normalized Y'Cb'Cr' values can be produced by the following Matlab code

a = 1.402; b = 1.772; c=-0.34414; d=-0.71414;

M2 = [1 0 a a ; 1 b 0 b; 1 c d (c+d); 0 0 0 -1];

M1 = [0.299 0.587 0.114 0; -0.1687 -0.3313 0.5 1; 0.5 -0.4187 -0.0813 1];

M = M1*M2


You should provide an input vector of the form:

   vin = [Y Cb Cr -128]


vout = M*vin;


For example vin = [156 144 145 -128]' produces the output :

M*[156 144 145 -128]'

ans =

177.7573
105.7629
129.4807


Rounding to integer will produce your expected result.

$$M_1= \begin{bmatrix} 0.2990 &~~~0.5870 &~~~0.1140 &0.0000\\ 0.1687 &-0.3313 &~~~0.5000 &1.0000\\ 0.5000 &-0.4187 &-0.0813 &1.0000\\ \end{bmatrix}$$

$$M_2= \begin{bmatrix} 1.000 &0.0 &1.402 &1.402\\ 1.000 &1.772 &0.000 &1.772\\ 1.000 &-0.34414 &-0.71414 &-1.0583\\ 0.000 &0.000 &0.000 &-1.000 \end{bmatrix}$$

• That works! Thank you so much I thought that clamping (0,255) would have been a problem to get a single forward transform but anyway image is still good. Thanks again – Eraclea Jul 29 '17 at 14:54
• I'm glad I could help! I hope so the floating point multiplications won't pose a serious problem for your micro? If so you can convert them into old-skool shifts if that's absolutely necesarry (not sure if that will improve dramatically though). In addition, I highly suggest you to look for the camera documentation to totally fix the problem from the camera driver by selecting different YCbCr internal encodings from an option switch. THat would relieve your burden to zero. – Fat32 Jul 29 '17 at 15:00
• Btw you may do the clamping at the final (corrected) Y'Cb'Cr' samples if necessary. – Fat32 Jul 29 '17 at 15:02
• I already checked the camera documentation and there's no option about ycbcr, but that's normal i guess, it was a really cheap camera. Floating points are not a problem since my micro (stm32f407) has a floating point unit, however doing that with integers and shift is way faster, like 2 times faster. – Eraclea Jul 29 '17 at 22:56