滤镜

滤镜其实是对原本的图像颜色进行调整。

图像构成

在一个图像文件中,它保存的数据主要分为两块:图像的信息图像的数据

图像的信息:它是一组让CPU和GPU在显示图像的时候基于这组信息显示的信息。

图像的数据:图像具体显示的像素点数据。

JPG的文件结构

images

如上图所示,它的部分16进制如下:

image-20201211104548456

对于一个JPG 文件来说,其文件头总是由位固定的字节来描述的:
十六进制数 FF D8 FF E0 00 10 4A 46 00 01

具体的格式信息,就不说啦。

颜色通道和颜色模式

颜色通道: 保存图像颜色信息的通道称为颜色通道。可以理解为记录色彩信息的那一段数据, 每个图像都有一个或者多个颜色通道,图像中默认的颜色通道信息取决于颜色模式。

颜色模式: 颜色模式可以理解为是一种将某种颜色表现为数字形式的模型,或者说是一种记录图像颜色的方式。分为:RGB模式、CMYK模式、HSB模式、Lab颜色模式、位图模式、灰度模式、索引颜色模式、双色调模式和多通道模式等。
实际上我们就认为,我要显示的色彩是用数字表示的,最经典的RGB模式我们可以理解为R(255) G(0) B(0) 当前这个像素显示,在识别的时候为红色,他由红 绿 蓝 三种色彩进行混合,显示出我们要的颜色其程度数值是0-255的范围

总结: 也就是说,其实图像的显示,每个点都是由模式所决定的色彩数值混合形成我们想要的颜色,那么我们的滤镜效果实现,其实实际上就是去对于颜色通道进行过滤操作,在其原本的模式数值上面进行操作,达到更改图像色彩效果的目的,这就是我们所为的滤镜。

颜色矩阵

在Android当中,他所采用的颜色模式是RGBA模式,也就是在红绿蓝的基础上加入了Alpha透明度的概念,那么也就是他现在是一个四通道的模式
在Android当中将图像信息获取出来时候,当前图像的颜色通道信息他用的是一个矩阵在进行保存。

img

上面这里看到的是一个四通道形式的表示方式,我门会发现在1-1、2-2、3-3、4-4 的位置都是一个1的数值,那么几个数值我们把他理解为颜色的系数,1为原本数值不动,若0.5那么当前对应的rgba四个选项按比例处理。
如果想要更改为半透明的,那么,当前a的值改为0.5。

但是如果在这种情况下:

  1. 红色 分量值更改为原来的2倍;
  2. 绿色分量增加100;

则用4阶矩阵的乘法无法实现,所以应该在四阶色彩变换矩阵上增加一个亚元坐标,来实现所列的矩阵运算:

在android当中真正的表现方式他应用了一个4*5的矩阵
image-20201211125055945

最后方加入一列,作为所为的亚元坐标,其实也就是分量值。

滤镜实现

对于矩阵的操作运算,在android中可以依赖一个API就行。

// 颜色通道过滤
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1, 0,0,0,0,
            0,0,0,0,0,
            0,0,0,0,0,
            0,0,0,1,0,
    });
  paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));

滤镜效果

下面各个效果,公共代码部分:

class FilterView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
 
    private val bitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.images)
    private val rectF: RectF = RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat())
    private val paint: Paint = Paint()
 
    init {
        setLayerType(LAYER_TYPE_HARDWARE, null) // 开启硬件加速
    }
 
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.translate(width / 4f, 0f)
        paint.reset()
        paint.color = Color.RED
        canvas.drawBitmap(bitmap, null, rectF, paint)
    }
}

原图:image-20201211144215697

红色

image-20201211144322349
// onDraw():
// 红色系数为1,其余2种系数为0,alpha 系数为1
val colorMartrix = ColorMatrix(
    floatArrayOf(
        1f, 0f, 0f, 0f, 0f,
        0f, 0f, 0f, 0f, 0f,
        0f, 0f, 0f, 0f, 0f,
        0f, 0f, 0f, 1f, 0f,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

绿色加100

image-20201211144812074
// onDraw():
// 红、绿、蓝系数为1,绿色分量加100,alpha 系数为1
val colorMartrix = ColorMatrix(
    floatArrayOf(
        1f, 0f, 0f, 0f, 0f,
        0f, 1f, 0f, 0f, 100f,
        0f, 0f, 1f, 0f, 0f,
        0f, 0f, 0f, 1f, 0f,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

底片效果

image-20201211145402759
// onDraw():
// 红、绿、蓝系数为-1,分量加255,alpha 系数为1
val colorMartrix = ColorMatrix(
    floatArrayOf(
        -1f, 0f, 0f,  0f, 255f,
        0f, -1f, 0f,  0f, 255f,
        0f, 0f, -1f, 0f,  255f,
        0f, 0f, 0f,  1f, 0f,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

缩放运算-- 颜色增强

image-20201211150121040
// onDraw():
val colorMartrix = ColorMatrix(
    floatArrayOf(
        1.2f, 0f, 0f, 0f, 0f,
        0f, 1.2f, 0f, 0f, 0f,
        0f, 0f, 1.2f, 0f, 0f,
        0f, 0f, 0f, 1.2f, 0f,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

灰色照片

去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,同时为了保证图像亮度不变,同一个通道里的R+G+B =1。

image-20201211153735131
// onDraw():
val colorMartrix =  ColorMatrix(
    floatArrayOf(
        0.213f, 0.715f,0.072f,0f,0f,
        0.213f, 0.715f,0.072f,0f,0f,
        0.213f, 0.715f,0.072f,0f,0f,
        0f,0f,0f,1f,0f,
    ))
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

发色效果

红绿色交换

image-20201211155717814
// onDraw():
val colorMartrix = ColorMatrix(
    floatArrayOf(
        0f,1f,0f,0f,0f,
        1f, 0f,0f,0f,0f,
        0f,0f,1f,0f,0f,
        0f,0f,0f,1f,0f,
    ));
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

复古效果

image-20201211160133715
// onDraw():
val colorMartrix = ColorMatrix(
    floatArrayOf(
        1 / 2f, 1 / 2f, 1 / 2f, 0f, 0f,
        1 / 3f, 1 / 3f, 1 / 3f, 0f, 0f,
        1 / 4f, 1 / 4f, 1 / 4f, 0f, 0f,
        0f, 0f, 0f, 1f, 0f,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)

颜色通道过滤

// onDraw():
val colorMartrix = ColorMatrix(
    floatArrayOf(
        1.3F,0,0,0,0,
        0,1.3F,0,0,0,
        0,0,1.3F,0,0,
        0,0,0,1,0,
    )
)
canvas.translate(0f, bitmap.height.toFloat())
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)