VirtualDub插件开发:YUV图像色相调整不影响亮度的实现问询
调整YUV空间UV分量色相的实现方案
嘿,这个需求我太熟悉了!你要在不影响亮度的前提下调整色相,刚好可以直接在YUV空间对UV分量做旋转变换——完全碰不到Y分量,完美契合你的要求。
核心原理
YUV色彩空间里,U和V分量构成了一个二维平面:每个(UV)点的角度对应色相,距离原点的距离对应饱和度。调整色相本质上就是把这个平面上的所有点旋转指定角度,完全不会改变Y(亮度)值。
你的UV取值范围是-0.5到+0.5,我们只需要基于这个范围做旋转计算即可,步骤如下:
具体实现步骤
把UV从字节值转成归一化范围:
你当前的U/V是0-255的字节值,先转成-0.5到+0.5的归一化值:float U_norm = (U / 255.0f) - 0.5f; float V_norm = (V / 255.0f) - 0.5f;应用旋转矩阵计算调整后的UV:
色相调整-45度,对应弧度是-π/4。旋转矩阵的公式是:U' = U_norm * cosθ - V_norm * sinθ
V' = U_norm * sinθ + V_norm * cosθ因为
cos(-45°)=sin(45°)=√2/2≈0.7071,sin(-45°)=-√2/2≈-0.7071,代入后可以简化为:const float sqrt2_over_2 = 0.70710678118f; // 预计算√2/2,提升性能 float U_rotated = U_norm * sqrt2_over_2 + V_norm * sqrt2_over_2; float V_rotated = -U_norm * sqrt2_over_2 + V_norm * sqrt2_over_2;把归一化值转回字节范围并 clamp:
旋转后的UV可能超出-0.5到+0.5的范围,转成0-255字节值时需要限制范围,避免颜色异常:int U_new = static_cast<int>( (U_rotated + 0.5f) * 255.0f ); int V_new = static_cast<int>( (V_rotated + 0.5f) * 255.0f ); // 确保值在0-255之间,需要包含<algorithm>头文件 U_new = std::clamp(U_new, 0, 255); V_new = std::clamp(V_new, 0, 255);
完整代码整合
结合你现有的代码,完整实现如下:
#include <algorithm> // 用于std::clamp // ... 你的现有代码 ... Pixel32 *dst= fa->dst.data; int U= (*dst>>16) & 0xff; int Y= (*dst>> 8) & 0xff; int V= (*dst ) & 0xff; // 色相调整-45度的核心逻辑 float U_norm = (U / 255.0f) - 0.5f; float V_norm = (V / 255.0f) - 0.5f; const float sqrt2_over_2 = 0.70710678118f; float U_rotated = U_norm * sqrt2_over_2 + V_norm * sqrt2_over_2; float V_rotated = -U_norm * sqrt2_over_2 + V_norm * sqrt2_over_2; int U_new = static_cast<int>( (U_rotated + 0.5f) * 255.0f ); int V_new = static_cast<int>( (V_rotated + 0.5f) * 255.0f ); U_new = std::clamp(U_new, 0, 255); V_new = std::clamp(V_new, 0, 255); // 写回调整后的像素值 *dst = (U_new << 16) | (Y << 8) | V_new;
额外注意事项
- 性能优化:如果是固定调整-45度,直接用预计算的
sqrt2_over_2比调用cos()/sin()函数快很多,适合插件这种对性能敏感的场景。 - 数据类型:一定要用浮点类型做中间计算,避免整数除法导致精度丢失。
- 范围限制:
std::clamp是C++17及以后的函数,如果你的编译器版本较低,可以手动实现范围限制:U_new = std::max(0, std::min(U_new, 255));
内容的提问来源于stack exchange,提问作者Captain Jack
相关产品推荐
相关产品推荐

