User Tools

RGB to YCbCr 4:4:4

Pixels are coming out of de-bayer as 12-bit per channel RGB triplets (36 bits total per pixel). For now what we get from the sensor is assumed to be linear-light data (so we have to apply a transform function first to be aligned with the BT.709 spec). This also relies on CMX being built with BT.709 primaries + D65.

This specification uses full-range (computer-range) YCbCr, not studio-range video levels.

This conversion will take as input \(RGB\) pixels as triplets of 12-bit unsigned integers in range \([0..4095]\) and produce an output of 12-bit per channel YCbCr of the following format: \[ Y12 \in [0..4095]\\ C_b12 \in [0..4095]\text{, neutral at }2048\\ C_r12 \in [0..4095]\text{, neutral at }2048 \]

Step 1: apply OETF

As the first step of the image processing pipeline we apply BT.709 OETF to convert from linear \(RGB\) (denoted as \(L\)) to \(R'G'B'\) (denoted as \(E\)). For each channel separately do the following: \[ E = \begin{cases} 4.5 \times L & \quad \text{if } L < 0.018\\ 1.099 \times L^0.45 - 0.099& \quad \text{if } L >= 0.018 \end{cases} \] Of course this should be implemented in FPGA as a LUT with \(4096\) entries using the following pseudocode to generate the table:

L = i / 4095
E = L < 0.018 ? 4.5 * L : 1.099 * L^0.45 - 0.099
LUT[i] = clamp12(E * 4095)

and then for each channel it is just a matter of picking up a value from that LUT, which is the application of the transform function needed to go from linear to non-linear representation (from \(RGB\) to \(R'G'B'\)).

Step 2: calculate luma Y12

We calculate pixel's luma using coefficients from the BT.709 standard (sometimes referred to as either Rec.709 or ITU-R 709). The spec defines those as: \[ K_r = 0.2126\\ K_g = 0.7152\\ K_b = 0.0722 \] so to avoid floating point calculations we are going to use Q18 format and calculate the value as: \[Y12 = clamp12((R' \times 55732 + G' \times 187485 + B' \times 18927 + 131072) >> 18)\]

Step 3: calculate chroma Cb/Cr12

First we need to get the deltas (both are signed values, so the bit shifting should do the right thing when going from Q18 to 12-bit signed integer): \[ \Delta B = B' - Y12\\ \Delta R = R' - Y12 \] and next, get the \(C_b\) and \(C_r\): \[ C_b12 = clamp12(2048 + [(\Delta B * 141272) >> 18])\\ C_r12 = clamp12(2048 + [(\Delta R * 166462) >> 18]) \] All chroma delta multiplications and right shifts are performed using signed arithmetic with arithmetic right shift

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

More information