1

I've implemented rgb->ycrcb and ycrcb->rgb conversion using JPEG conversion formulae from
http://www.w3.org/Graphics/JPEG/jfif3.pdf
(the same at: http://en.wikipedia.org/wiki/YCbCr (JPEG conversion)).

When checking whether results are correct (original->YCrCb->RGB), some of pixels differ by one, e.g 201->200.

Average percent of precision errors is 0.1%, so it's not critical.

/// converts RGB pixel to YCrCb using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 rgb2ycrcb(int r, int g, int b)
{
    int y =  round(0.299*r + 0.587*g + 0.114*b) ;
    int cb = round(128.0 - (0.1687*r) - (0.3313*g) + (0.5*b));
    int cr = round(128.0 + (0.5*r) - (0.4187*g) - (0.0813*b));
    return ivect4(y, cr, cb, 255);
}
/// converts YCrCb pixel to RGB using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 ycrcb2rgb(int y, int cr, int cb)
{
    int r = round(1.402*(cr-128) + y);
    int g = round(-0.34414*(cb-128)-0.71414*(cr-128) + y);
    int b = round(1.772*(cb-128) + y);
    return ivect4(r, g, b, 255);
}

I use round formula:
floor((x) + 0.5)

When using other types of rounding, e.g. float(int), or std::ceil(), results are even worse.

So, does there exist the way to do YCrCb <-> RGB conversion without loss in precision?

4 Answers 4

4

The problem isn't rounding modes.

Even if you converted your floating point constants to ratios and used only integer math, you'd still see different values after the inverse.

To see why, consider a function where I tell you I'm going to shift the numbers 0 through N to the range 0 through N-2. The fact is that this transform is just doesn't have an inverse. You can represent it more or less exactly with a floating point computation (f(x) = x*(N-2)/N), but some of the neighboring values will map to the same result in integer math (pigeonhole principle!). This is a simplification and "compresses" the range, but the same thing happens in arbitrary affine transforms like this one you are using.

If you had r, g, b in floating point, and kept it that way until you quantized to integer, that would be a different story - but in integers you will necessarily always see some difference between the original and the inverse.

1

Only about 60% of all RGB values can be represented in YCbCr space when using the same amount of bits for both triplets. This means the most damage happens in RGB->YCbCr when you take a 3*8 bit RGB triplet, convert and round it back to 3*8 bits of precision. The trick is to store the YCbCr triplet at a higher precision until it's time to do forward DCT. There, the data needs to be scaled up anyway, so you can do e.g. 16 bit * 16 bit -> MSB16 multiplies, which are well supported by various SIMD instruction sets.

At the decoder it's the reverse: The results of inverse DCT have to be stored at higher precision until it's time to do the YCbCr->RGB conversion.

This doesn't make the process lossless, but for JPEG, it may buy a few dB of PSNR at the extreme high end of the quality scale, i.e. where the difference can't be seen with a naked eye but can be measured.

1

Yes, supposedly JPEG XR defines a color conversion that is reversible. The code is open source if you want to investigate in depth how they're doing it. The method is loosely described on the Wiki-page I linked to.

Also this SO post might give you some insights.

0

Another problem is that there is not a 1 to 1 mapping between rgb and YCbCR. There are YCbCr values with no corresponding RGB value and RBG values with no corresponding YCbCR values.

2
  • In HSV description it's stated, and there is handling of these cases, but in YCrCb it wasn't described.
    – olha
    May 7, 2015 at 10:02
  • 1
    The way you handle that situation in YCbCr is to use the closest color. You will get component values outside the range 0-255 in the conversion. You clamp those to the range. May 7, 2015 at 14:54

Your Answer

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

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