图像结构
我们首先了解一下图像的构成,例如一张PNG图片:
图片文件头由位固定的字节来描述的,以便向外说明这个文件是一个PNG文件。
十进制数
137 80 78 71 13 10 26 10
十六进制数
89 50 4E 47 0D 0A 1A 0A
用UE打开一个PNG文件的内容为:
可以看到都为十六进制的数据,我们不知道这些数据是什么,假定第一行的数据是这个PNG的标志,第2-8行可能记录的是解析规则等信息,再之后的则为数据,那么
在一个图像文件中,总体包含的数据分为两部分:
1.文件的标志信息;
2.文件的数据信息;
标志的信息主要用来识别该文件是不是PNG文件,而数据块则储存了图片的图像信息;
PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是必需的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。虽然PNG文件规范没有要求PNG编译码器对可选数据块进行编码和译码,但规范提倡支持可选数据块。
每个数据块都由4个域组成:

关键数据块

IHDR
文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

颜色通道
保存图像颜色信息的通道称为颜色通道。
RGB color有合成意义的变化(color channel),就是人有合成意义地(只用肢体或使用工具)将红蓝绿三种(实色料或颜色)合成出(一个或多个实色料空间显示、阻挡显示、隐藏、消失,从合成后可以赋予意义、认为无意义、没有赋予的意义、没有发现的意义、没有认同的意义等多种意义;一种颜色或多种颜色显示、阻挡显示、隐藏、消失,从合成后可以赋予意义、认为无意义、没有赋予的意义、没有发现的意义、没有认同的意义等多种意义)。
每个图像都有一个或多个颜色通道,图像中默认的颜色通道数取决于其颜色模式,即一个图像的颜色模式将决定其颜色通道的数量。例如,CMYK图像默认有4个通道,分别为青色、洋红、黄色、黑色。在默认情况下,位图模式、灰度、双色调和索引颜色图像只有一个通道。RGB和Lab图像有3个通道,CMYK图像有4个通道。
颜色模式
颜色模式,是将某种颜色表现为数字形式的模型,或者说是一种记录图像颜色的方式。分为:RGB模式、CMYK模式、HSB模式、Lab颜色模式、位图模式、灰度模式、索引颜色模式、双色调模式和多通道模式。
总结
颜色通道取决于颜色模式。
通俗点说,我们要显示图片中的色彩的时候,用数字表示,例如RGB模式,例如R255-G0-B0用来显示当前像素的色彩,在显示的时候为红色,RGB为红绿蓝三种色彩进行混合,其对应颜色数值的大小范围为0~255, 即每个点都是由颜色模式所决定的颜色通道(色彩数值)混合形成我们想要的颜色,而要实现滤镜效果,其实就是对颜色通道值进行处理,在其原本的通道数值进行更改,达到更改图像色彩效果的目的,这就是我们所谓的滤镜。
颜色矩阵
在安卓中,颜色模式为RGBA,即在RGB模式上加了一个A(alpha)透明值,即为一个四通道的模式。
在安卓中有一个类叫ColorMatrix(颜色矩阵),其用一个4x5矩阵来进行描述,用于转换位图的颜色和alpha分量。
矩阵可以作为单个数组传递,并作如下处理:
ColorMatrix类的注解为:
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
当应用到颜色 [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;
由此产生的 [R,A,G,B]的值在0~255之间
我们可以理解为
安卓中的颜色矩阵是一个4×5的数字矩阵:

会以一维数组的形式来存储:(float[]类型)
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
即
new float[]{
a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t
};
矩阵运算

当矩阵A的列数等于矩阵B的行数时,A与B可以相乘。
矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。
乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。
颜色矩阵运算
我们可通过ColorMatrix类生成指定的颜色矩阵A,

与颜色通道的原始色彩矩阵进行矩阵乘法运算。
这里有一个色彩矩阵分量C,代表着我们颜色通道的原始色彩:

矩阵R则代表通过矩阵乘法运算AC而得到的新的颜色:

R' = aR + bG + cB + dA + e;
G' = fR + gG + hB + iA + j;
B' = kR + lG + mB + nA + o;
A' = pR + qG + rB + sA + t;
我们这里可以看到,最后会加上最后一列的e, j, o, t,这是因为在安卓中(这个是安卓的颜色矩阵规则),前4列组成的才是四阶颜色矩阵:

而最后一列则是代表增量值,即4阶矩阵相乘后再加上这个增量,从而得到最终的颜色值。
颜色矩阵中,
+ 第一行决定红色值
+ 第一行决定绿色值
+ 第一行决定蓝色值
+ 第一行决定透明值
下面这个为原始矩阵,即对原色值不做任何改变:

下面我们通过代码来进行实现
首先我们先定义主页面
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:gravity="center"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_filter"
android:text="滤镜"
android:textSize="22sp"
android:onClick="onStartFilterActivity"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_custom"
android:layout_marginTop="10dp"
android:text="自定义"
android:textSize="22sp"
android:onClick="onStartCustomActivity"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onStartFilterActivity(View view) {
startActivity(new Intent(this, FilterActivity.class));
}
public void onStartCustomActivity(View view) {
startActivity(new Intent(this, CustomFilterActivity.class));
}
}

实现两种功能,一个是采用固定的滤镜方式,一个是采用自定义的滤镜方式。
固定的滤镜方式
布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_tip1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="原图"
android:layout_marginLeft="10dp"
android:textColor="@android:color/holo_red_dark"
android:textSize="22sp" />
<ImageView
android:id="@+id/tv_src"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pic_xxx_01" />
<TextView
android:id="@+id/tv_tip2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="效果图"
android:textColor="@android:color/holo_red_dark"
android:textSize="22sp" />
<com.iigo.paint.FilterView
android:id="@+id/fv_filter"
app:img_id="@mipmap/pic_xxx_0

本文详细介绍了如何在安卓中利用颜色矩阵实现各种图像滤镜效果,包括底片、复古、美颜、黑白及自定义滤镜等。通过调整颜色矩阵中的参数,可以轻松改变图像的颜色属性。
最低0.47元/天 解锁文章
419

被折叠的 条评论
为什么被折叠?



