暗黑模式
矩阵卷积滤镜
前端教程SVG
<feConvolveMatrix>
矩阵卷积滤镜把输入图形的每个像素周围的某些像素组成一个矩阵,然后再乘以一个 n×m 的矩阵(该矩阵是自定义的,称为卷积核 convolution kernel)。该滤镜可以实现模糊、边缘检测、锐化、压花和斜角等效果。
原理解释
我们通过举例子来解释卷积矩阵滤镜的原理:
假设输入图片为以下 5×5 像素的图片,我们称为 SOURCE:
我们把像素点的数值标注出来:
为了更加简化说明,我们只以 G 通道为例,把上图中 G 值取出来,得到以下矩阵:
我们以上图矩阵中(x,y)=(2,3)即第2行第3列作为目标像素为例,看这个像素点是如何经过卷积变换的。
以下是卷积变换公式:
- SOURCE(X, Y)表示输入图片像素矩阵的第 X 行第 Y 列,即目标像素
- COLOR(X, Y)表示输入图片第X行Y列像素经过变换之后的值
- SOURCE 为输入图片的像素矩阵,例如前面图片的 5×5 矩阵
- targetX, targetY 决定了把目标像素周围的哪些像素作为输入矩阵参与计算
- targetX 取值范围为 0 ≤ targetX < orderX,默认为 floor(orderX / 2)
- targetY 取值范围为 0 ≤ targetY < orderY,默认为 floor(orderY / 2)
- 公式为 SOURCE(X-targetX+j, Y-targetY+i)
- targetX, targetY 决定了把目标像素周围的哪些像素作为输入矩阵参与计算
- ALPHA 为输入图片的 alpha 通道矩阵
- bias 为结果偏移量,默认为 0
- K 为卷积核矩阵
- orderX 是该矩阵的列数
- orderY 是该矩阵的行数
- divisor 为除数,默认为卷积矩阵所有元素之和
- 另外请注意:SOURCE * K
- 这里是矩阵点乘,而不是相乘(或 ×乘)
- 也就是2个矩阵维度一致,对应元素做乘法,得到的结果还是一样维度的矩阵
我们以下面的参数为例:
(X,Y) = (2,3) ,即输入图片的第2行第3列像素点,G值=176
K= 1 2 3
4 5 6 即 2×3 的矩阵,此时 orderX=3,orderY=2
targetX=1
targetY=1
divisor取默认值:1+2+3+4+5+6 = 21
bias=0
1
2
3
4
5
6
7
2
3
4
5
6
7
代入参数后的公式:
- 上图的蓝色框为实际参与计算的区域,也就是(2,3)的周围像素(调整 targetX targetY 的值,该区域会变动)
- 红色框的表达式,意味着将卷积矩阵旋转180°
结果为:
( 176*6 + 176*5 + 176*4
+ 192*3 + 192*2 + 192*1 ) / 21 = 180
1
2
2
- SOURCE(2,3)的 G 通道原值为 176,经过卷积变换后为 180
至此,原理解释完毕了!
基本语法
xml
<filter id="emboss">
<feConvolveMatrix kernelMatrix="1 2 3
4 5 6"
order="3" divisor="" bias="0" targetX="" targetY="" preserveAlpha="true|false" />
</filter>
1
2
3
4
5
2
3
4
5
order="size|orderX orderY"
卷积矩阵的维度,格式为1个数值或2个数值- 当为1个数值时,例如
order=3
表示矩阵的行列都是 3,即 3×3 矩阵 - 当为2个数值时,例如
order=3 2
表示矩阵的列数是 3、行数是 2,即 2×3 矩阵 - 默认为 3,即表示卷积矩阵的维度为 3×3
- 此值不应该设置太大,否则会影响性能
- 当为1个数值时,例如
kernelMatrix="list of numbers"
m×n
卷积矩阵的内容,用空格或逗号间隔每个矩阵元素divisor
卷积公式中的除数,默认为卷积矩阵所有数值的和(如何和是0,由于除数不能是 0,所以此时 divisor=1)- 以上面的语法为例,此时默认 divisor = 1+2+3+...+6 = 21
bias
卷积公式中的偏移量,默认为 0targetX
targetY
决定了目标像素周围的哪些像素参与计算preserveAlpha="true|flase(默认)
是否保留 alpha 通道不变true
alpha 通道不参与计算,即原图的 alpha 通道保持不变false
与前面相反,即原图的 alpha 通道也像 RGB 通道一样参与变换
edgeMode="duplicate | wrap | none(默认)"
- 有个特殊情况,当目标像素是(0, 0) 或 (最后一行,最后一列)时,也就是目标元素在边缘时,那么目标元素周围可能没有元素了,此时通过该参数确定使用何种策略解决此问题
none
用RGBA(0,0,0,0)扩展原始输入图片duplicate
重复边缘像素以扩展图片wrap
用对角边缘的像素来扩展图片
示例
通过以下的 codepen 来交互感受一下卷积矩阵滤镜吧:
- 这里我们使用了 3×3 的卷积矩阵
- 左图为原图片,右图为滤镜后的图片