Paul Haeberli
1993 年 11 月
介绍
四乘四矩阵通常用于转换几何以进行 3D 渲染。这些矩阵还可用于转换 RGB 颜色、缩放 RGB 颜色以及控制色调、饱和度和对比度。使用矩阵最重要的优点是可以使用标准矩阵乘法组合任意数量的颜色变换。
请注意,要使这些操作正确,我们必须对线性亮度值进行操作。如果输入图像在非线性亮度空间中,则在使用这些矩阵运算之前,必须将 RGB 颜色转换为线性空间。
颜色转换
RGB 颜色由四乘四矩阵转换,如下所示:
xformrgb(mat, r, g, b, tr, tg, tb)
float mat[4][4];
float r,g,b;
float *tr,*tg,*tb;
{
*tr = r*mat[0][0] + g*mat[1][0] + b*mat[2][0] + mat[3][0];
*tg = r*mat[0][1] + g*mat[1][1] + b*mat[2][1] + mat[3][1];
*tb = r*mat[0][2] + g*mat[1][2] + b*mat[2][2] + mat[3][2];
}
身份
这是单位矩阵:
float mat[4][4] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
};
通过单位矩阵变换颜色将使它们保持不变。
改变亮度
要缩放 RGB 颜色,使用这样的矩阵:
float mat[4][4] = {
rscale, 0.0, 0.0, 0.0,
0.0, gscale, 0.0, 0.0,
0.0, 0.0, bscale, 0.0,
0.0, 0.0, 0.0, 1.0,
};
其中rscale
、gscale
和bscale
指定缩放颜色的 r、g 和 b 分量的程度。这可以用来改变图像的色彩平衡。
实际上,这计算:
tr = r*rscale;
tg = g*gscale;
tb = b*bscale;
转换为亮度
要将彩色图像转换为黑白图像,使用此矩阵:
float mat[4][4] = {
rwgt, rwgt, rwgt, 0.0,
gwgt, gwgt, gwgt, 0.0,
bwgt, bwgt, bwgt, 0.0,
0.0, 0.0, 0.0, 1.0,
};
在哪里
- rwgt 为 0.3086
- gwgt 是 0.6094
- 体重为 0.0820
这是亮度向量。请注意,我们不使用标准 NTSC 权重 0.299、0.587 和 0.114。NTSC 权重仅适用于伽马 2.2 颜色空间中的 RGB 颜色。对于线性 RGB 颜色,上述值更好。
实际上,这计算:
tr = r*rwgt + g*gwgt + b*bwgt;
tg = r*rwgt + g*gwgt + b*bwgt;
tb = r*rwgt + g*gwgt + b*bwgt;
修改饱和度
为了使 RGB 颜色饱和,使用了这个矩阵:
float mat[4][4] = {
a, b, c, 0.0,
d, e, f, 0.0,
g, h, i, 0.0,
0.0, 0.0, 0.0, 1.0,
};
其中常数来源于饱和值s
,如下所示:
a = (1.0-s)*rwgt + s;
b = (1.0-s)*rwgt;
c = (1.0-s)*rwgt;
d = (1.0-s)*gwgt;
e = (1.0-s)*gwgt + s;
f = (1.0-s)*gwgt;
g = (1.0-s)*bwgt;
h = (1.0-s)*bwgt;
i = (1.0-s)*bwgt + s;
这个饱和度矩阵的一个很好的特性是保持输入 RGB 颜色的亮度。此矩阵还可用于通过指定饱和度值 -1.0 来补充图像中的颜色。
请注意,当 s 设置为 0.0 时,该矩阵正是上述“转换为亮度”矩阵。当 s 设置为 1.0 时,矩阵变为恒等式。所有饱和度矩阵都可以通过在这两个矩阵之间进行插值或外插得到。
这在关于通过插值和外插进行图像处理的注释中进行了更详细的讨论。
将偏移应用到颜色组件
为了抵消图像中颜色的 r、g 和 b 分量,使用此矩阵:
float mat[4][4] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
roffset,goffset,boffset,1.0,
};
这可以与颜色缩放一起使用以改变 RGB 图像的对比度。
简单的色相旋转
为了旋转色调,我们对对角线向量 [1.0 1.0 1.0] 执行 RGB 颜色的 3D 旋转。转换矩阵的推导如下所示:
如果我们有函数:
identmat(mat)
: 创建一个单位矩阵。
xrotatemat(mat,rsin,rcos)
:乘以围绕 x(红色)轴旋转的矩阵。
yrotatemat(mat,rsin,rcos)
:乘以围绕 y(绿色)轴旋转的矩阵。
zrotatemat(mat,rsin,rcos)
:乘以围绕 z(蓝色)轴旋转的矩阵。
然后可以像这样构造一个围绕 1.0,1.0,1.0 对角线旋转的矩阵:
首先我们制作一个单位矩阵
identmat(mat);
将灰度向量旋转为正 Z
mag = sqrt(2.0);
xrs = 1.0/mag;
xrc = 1.0/mag;
xrotatemat(mat, xrs, xrc);
mag = sqrt(3.0);
yrs = -1.0/mag;
yrc = sqrt(2.0)/mag;
yrotatemat(mat, yrs, yrc);
旋转色调
zrs = sin(rot*PI/180.0);
zrc = cos(rot*PI/180.0);
zrotatemat(mat, zrs, zrc);
将灰色矢量旋转回原位
yrotatemat(mat, -yrs, yrc);
xrotatemat(mat, -xrs, xrc);
生成的矩阵将旋转输入 RGB 颜色的色调。120.0 度的旋转将准确地将红色映射到绿色,将绿色映射到蓝色,将蓝色映射到红色。这种变换有一个问题,但是输入颜色的亮度没有被保留。这可以通过以下改进来解决:
在保持亮度的同时进行色相旋转
我们制作一个单位矩阵
识别码(mmat);
将灰度向量旋转为正 Z
mag = sqrt(2.0);
xrs = 1.0/mag;
xrc = 1.0/mag;
xrotatemat(mmat, xrs, xrc);
mag = sqrt(3.0);
yrs = -1.0/mag;
yrc = sqrt(2.0)/mag;
yrotatemat(mmat, yrs, yrc);
matrixmult(mmat, mat, mat);
剪切空间使亮度平面水平
xformrgb(mmat,rwgt,gwgt,bwgt,&lx;,&ly;,&lz;);
zsx = lx/lz;
zsy = ly/lz;
zshearmat(mat,zsx,zsy);
旋转色调
zrs = sin(rot*PI/180.0);
zrc = cos(rot*PI/180.0);
zrotatemat(mat,zrs,zrc);
取消剪切空间以放回亮度平面
zshearmat(mat,-zsx,-zsy);
将灰色矢量旋转回原位
yrotatemat(mat, -yrs, yrc);
xrotatemat(mat, -xrs, xrc);
结论
我已经介绍了几种可以应用于 RGB 颜色的矩阵变换。每个颜色变换由一个 4 x 4 矩阵表示,类似于通常用于变换 3D 几何的矩阵。
这些转换允许我们单独调整图像对比度、亮度、色调和饱和度。此外,颜色矩阵变换以类似于几何变换的方式连接。任何操作序列都可以使用矩阵乘法组合成一个矩阵。