Android | ColorMatrix 方法详解与示例

432 阅读5分钟

ColorMatrix介绍

ColorMatrix 是一个用于操作位图颜色分量的 4x5 矩阵类。常用于图像的颜色变换、饱和度调整、灰度处理、反转色、颜色通道旋转等操作。为什么 ColorMatrix 必须是 4x5 的矩阵形式呢?是为了支持颜色和 alpha 通道的线性变换,矩阵形式如下:

[ a, b, c, d, e,  //表示的红色R
  f, g, h, i, j,     //表示的绿色G
  k, l, m, n, o, //表示的蓝色B
  p, q, r, s, t ] //表示颜色的透明度A

这可以看作一个线性变换 + 平移,对一个颜色 [R, G, B, A] 应用此矩阵后,新的颜色 [R', G', B', A'] 的计算方式如下:

R' = a*R + b*G + c*B + d*A + e
G' = f*R + g*G + h*B + i*A + j
B' = k*R + l*G + m*B + n*A + o
A' = p*R + q*G + r*B + s*A + t

这表示每个输出分量都可以由输入的 RGBA 和常数项共同线性组合而成。其中,前 4 列对应于输入的 R、G、B、A 通道的乘法系数;第 5 列表示一个偏移量(即常数项),可以用于亮度调整、反转色等非线性变换。先给出一个原图如下:

原图

后面对图片的操作都是基于此图,比如做颜色反转:

val invert = ColorMatrix(
    floatArrayOf(
        -1f, 0f, 0f, 0f, 255f,  // Red 通道:-R + 255
        0f, -1f, 0f, 0f, 255f,  // Green 通道:-G + 255
        0f, 0f, -1f, 0f, 255f,  // Blue 通道:-B + 255
        0f, 0f, 0f, 1f, 0f      // Alpha 通道:保持不变
    )
)
mImgView.colorFilter = ColorMatrixColorFilter(invert)

为什么上述设置可以做到颜色反转,以 R 通道为例:

  • 如果 R = 0 → 输出R' = 255
  • 如果 R = 255 → 输出R' = 0
  • 如果 R = 100 → 输出R' = 155

这样就实现了颜色取反:反转 = 255 - 原值,上述代码效果如下:

反转

核心方法详解与示例

1. reset() - 重置为单位矩阵

public void reset()

将当前矩阵重置为单位矩阵(无变换),示例:

val matrix: ColorMatrix = ColorMatrix()
matrix.reset()

单位矩阵的形式如下:

1f, 0f, 0f, 0f, 0f, // Red 输出 = R * 1 + 0 = R 0f, 1f, 0f, 0f, 0f, // Green 输出 = G * 1 + 0 = G 0f, 0f, 1f, 0f, 0f, // Blue 输出 = B * 1 + 0 = B 0f, 0f, 0f, 1f, 0f // Alpha 输出 = A * 1 + 0 = A

该矩阵下不对图像进行任何变换,即:输出颜色 = 原始颜色,完全保持图像原样。

2. setScale() - 设置通道缩放

public void setScale(float rScale, float gScale, float bScale, float aScale)

设置通道缩放,参数rScale, gScale, bScale, aScale 分别对应缩放红、绿、蓝、透明度通道,如:

val matrix = ColorMatrix()
matrix.setScale(1f, 1f, 1f, 0.5f) //让alpha半透明

alpha透明度

其他调用方式示例:

变亮: setScale(1.5f, 1.5f, 1.5f, 1f)

变暗: setScale(0.5f, 0.5f, 0.5f, 1f)

泛红: setScale(2f, 1f, 1f, 1f)

去除某个颜色通道: setScale(1f, 0f, 1f, 1f)

设置半透明: setScale(1f, 1f, 1f, 0.5f)

3. setSaturation() - 设置饱和度

public void setSaturation(float sat)

设置图像的饱和度: 0 = 灰度,1 = 原图,>1 = 更鲜艳,如:

val matrix = ColorMatrix()
matrix.setSaturation(0f) // 变成灰度图像

saturation对比

4. setRotate() - 颜色通道旋转

public void setRotate(int axis, float degrees)

在颜色空间中,围绕某一个颜色通道(R/G/B)轴,对另外两个颜色通道做二维旋转操作,从而达到色调变化的效果。

  • axis 参数
含义实际效果
0红色 (R ) 通道旋转改变 绿色 (G)蓝色 (B) 的混合
1绿色 (G) 通道旋转改变 红色 (R )蓝色 (B) 的混合
2蓝色 (B) 通道旋转改变 红色 (R )绿色 (G) 的混合

⚠️ 注意axis不能取除 0、1、2 以外的值,否则会抛出 java.lang.RuntimeException

  • degrees参数(旋转角度)

表示围绕指定颜色通道的角度旋转,单位是角度,支持任意正负角度(如 30f-90f360f720f),会自动按三角函数周期性转换(360°周期)。

那么什么是“围绕颜色通道轴旋转”呢?可以把颜色 [R, G, B, A] 看成一个 4 维向量,
ColorMatrix.setRotate(axis, degrees) 是对 RGB 中的两个颜色分量做二维旋转,保留轴向通道不变

比如:setRotate(0, 90f) 就是绕 R 轴旋转 90°,相当于:红色 R 分量保持不变,对 G 和 B 分量执行二维旋转 90°,二维旋转矩阵:

[x', y'] = [ cos(θ)  -sin(θ) ] [x]
           [ sin(θ)   cos(θ) ] [y]

作用于颜色:

G' = cos(90°) * G - sin(90°) * B = -B  
B' = sin(90°) * G + cos(90°) * B = G  
R' = R

即:

输入:[R, G, B]
输出:[R, -B, G]

颜色就发生了扭转,产生了新的视觉滤镜效果,再比如:

val matrix = ColorMatrix()
matrix.setRotate(1, 45f) //绕绿色通道旋转 45 度
imageView.colorFilter = ColorMatrixColorFilter(matrix)

上述代码会让 红色 R 与蓝色 B 混合变色,绿色 G 保持不变,整体色调发生偏移。

rotate

5. setConcat() - 矩阵乘法(复合变换)

public void setConcat(ColorMatrix a, ColorMatrix b)

组合两个矩阵,先应用 b,再应用 a,示例:

val scale = ColorMatrix().apply { setScale(1.2f, 1.2f, 1.2f, 1f) }
val saturation = ColorMatrix().apply { setSaturation(2.0f) }

val result = ColorMatrix()
result.setConcat(scale, saturation)

先对图像进行“饱和度提升”,再做“亮度缩放”。

6. postConcat() 和 preConcat()

public void postConcat(ColorMatrix postMatrix)
public void preConcat(ColorMatrix preMatrix)

链式拼接变换:

  • postConcat 是 result = postMatrix × this
  • preConcat 是 result = this × postMatrix

示例:

val matrix = ColorMatrix().apply {
   setSaturation(0f) //变灰
}
val scale = ColorMatrix().apply {
   setScale(2f, 2f, 2f, 1f) //增强亮度
}
matrix.postConcat(scale)

上述代码先执行变灰操作,在执行增强亮度操作。如果改成preConcat,顺序反之。

总结

ColorMatrix 是一个功能强大的图像处理工具。它以 4x5 矩阵的形式,支持 RGB 和 Alpha 通道的线性变换与偏移,可完成色彩增强、去饱和、通道调换、图像反色等高级操作,适合搭配 ColorMatrixColorFilter 使用于 PaintImageView 等场景。