====== Hue rotation ====== "Hue rotation" is a global (every pixel) shift of the image's color spectrum by a given radial offset (considering the [[https://simple.wikipedia.org/wiki/Color_wheel|color wheel]]). ===== In RGB color space ===== To rotate the color vector by an angle \(\Theta\) is to rotate the RGB cube around the \((0,0,0)-(1,1,)\) diagonal axis, for which the [[https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle|rotation matrix]] looks like the following: \[ cos_1 = cos(\Theta) \\ cos_2 = \frac{1 - cos_1}{3} \\ sin_1 = sin(\Theta)\sqrt{1/3} \\ \begin{bmatrix} cos_1 + cos_2 & cos_2 - sin_1 & cos_2 + sin_1 \\ cos_2 + sin_1 & cos_1 + cos_2 & cos_2 - sin_1 \\ cos_2 - sin_1 & cos_2 + sin_1 & cos_1 + cos_2 \end{bmatrix} \] In our codebase the Hue adjustment is a 14-bit signed integer in range \([-8192..8191]\) that corresponds to \([-180°..+180°)\). M.B. this does **not** take into account the fact that different chroma components contribute differently to the luma of the pixel. A more correct implementation must first separate luma and chroma, perform rotation on chroma, and then convert back to RGB triplet, but that is way too expensive to perform in-line during video transmission. ===== In HSL color space ===== Really, no magic here, once you process the image in HSL color space. The operation is as trivial as adding or subtracting a specified value from the pixel's \(H\) component: // pseudo-code void hue_rotation(/*array of pixels*/image, double _hue){ for(const & pixel: image){ pixel.hue = std::clamp(pixel.hue + _hue, 0., 360.); // hue is in range [0..360]° } }