2
$\begingroup$

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)?

An example of a bad img

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

$\endgroup$
5
  • $\begingroup$ 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. $\endgroup$
    – Fat32
    Jul 28, 2017 at 23:22
  • $\begingroup$ Added in the post $\endgroup$
    – Eraclea
    Jul 28, 2017 at 23:52
  • $\begingroup$ 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? $\endgroup$
    – Fat32
    Jul 29, 2017 at 0:43
  • $\begingroup$ 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 $\endgroup$
    – Eraclea
    Jul 29, 2017 at 2:41
  • $\begingroup$ 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. $\endgroup$
    – Fat32
    Jul 29, 2017 at 13:02

1 Answer 1

0
$\begingroup$

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]

Then your output will be;

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} $$

$\endgroup$
4
  • $\begingroup$ 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 $\endgroup$
    – Eraclea
    Jul 29, 2017 at 14:54
  • $\begingroup$ 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. $\endgroup$
    – Fat32
    Jul 29, 2017 at 15:00
  • $\begingroup$ Btw you may do the clamping at the final (corrected) Y'Cb'Cr' samples if necessary. $\endgroup$
    – Fat32
    Jul 29, 2017 at 15:02
  • $\begingroup$ 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. $\endgroup$
    – Eraclea
    Jul 29, 2017 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.