====== 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 [[https://en.wikipedia.org/wiki/Rec._709|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**