什么是颜色矩阵?
矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,而颜色矩阵就是将颜色rgba值通过矩阵计算来进行系列的处理。例如:
| a b c d e | | R |
A = | f g h i j | B = | G |
| k l m n o | | B |
| p q r s t | | A |
| 1 |
A是需要对图片颜色值进行处理的5x4变换矩阵,B是原RGBA的颜色值(因为A是5x4的矩阵,所以B最后添加1来计算A的偏移值),而AxB(矩阵相乘)会得到处理后的1x4 rgba色值矩阵C。
玩过ps的都应该知道图片调整里有个玩法叫通道混合,通过改变不同通道中的值来调整图片的风格,而颜色矩阵计算的原理与其相似,下面我们简单介绍一下变换矩阵A中各值的含义:
- 第一行为红色通道的值。
- 第二行为绿色通道的值。
- 第三行为蓝色通道的值。
- 第四行为透明度的调整值。
- 每行元素从左至右分别表示
R G B A和偏移值。
在SVG中使用颜色矩阵
SVG有提供支持颜色变换矩阵的<feColorMatrix>标签,只需将变换矩阵A放放入values属性中即可,例如图片去色:
<svg width="1024" height="640" viewBox="0 0 1024 640" id="fecolor-test" preserveAspectRatio="xMidYMid slice">
<defs>
<filter id="fecolor-filter">
<feColorMatrix type="matrix" values=
"0.3086 0.6094 0.0820 0 0
0.3086 0.6094 0.0820 0 0
0.3086 0.6094 0.0820 0 0
0 0 0 1 0" />
</filter>
</defs>
<image width="1024" height="640" filter="url(#fecolor-filter)" href="https://static.pexels.com/photos/7976/pexels-photo.jpg" />
</svg>
<image width="1024" height="640" src="https://static.pexels.com/photos/7976/pexels-photo.jpg" />
在Canvas中使用颜色矩阵
canvas对图片数据也有相当强大的处理功能,能够从像素级别操作位图,当然[lte ie8]不支持。
需要了解的函数有三个:
ctx.createImageData(width,height);// 用于创建ImageData对象ctx.getImageData(x,y,width,height);// 用于从canvas中获取ImageData对象ctx.putImageData(imagedata, x, y, dx, dy, width, height);// 用于将ImagaData对象的数据填写到 canvas中,起到覆盖canvas中原图像的作用,可以只输入前三个参数。参数分别是:用于提供填充图像数据的imagedata对象,imagedata对象左上角相对于canvas左上角的坐标x,y,在canvas上用来填充imagedata区域的左上角相对imagedata对象左上角的坐标x,y(相对于canvas左上角),填充区域的长度和宽度。
我们将图片绘制到canvas中,然后通过ctx.getImageData获取图片颜色信息
// 写一个简单的矩阵乘法
function matrixMath(a, b) {
return a.map(x => x.reduce((ix, _, i) => {
if (b[0][i]) {
ix.push(b.reduce((iy, cy, y) => {
iy += cy[i] * x[y];
return iy;
}, 0));
}
return ix;
}, []));
}
// 褪色矩阵
const matrixA = [
[0.3086, 0.6094, 0.0820, 0, 0],
[0.3086, 0.6094, 0.0820, 0, 0],
[0.3086, 0.6094, 0.0820, 0, 0],
[0, 0, 0, 1, 0]
]
// 读取ImageDatas
const ImageData = ctx.getImageData(0,0,canvas.width,canvas.height)
const colorBuffer = ImageData.data
// imageDatas为图片每个像素的RGBA值按顺序排列的Uint8ClampedArray数组。
for( let i = 0; i - colorBuffer.length; i += 4){
let matrixB = [
[colorBuffer[i]],
[colorBuffer[i + 1]],
[colorBuffer[i + 2]],
[colorBuffer[i + 3]],
[1]
]
let [r, g, b, a] = matrixMath(matrixA, matrixB)
colorBuffer[i] = r[0]
colorBuffer[i + 1] = g[0]
colorBuffer[i + 2] = b[0]
colorBuffer[i + 3] = a[0]
}
ctx.putImageData(ImageData, 0, 0)
效果展示

0条评论