本文主要是介绍Android学习笔记之ColorMatrix、图像处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
飞呀
- 1.色彩矩阵
- 1.1改变偏移量
- 1.2改变颜色系数
- 2.使用ColorMatrix来改变图片的色光属性
- 2.1 色调
- 2.2 饱和度
- 2.3 亮度
- 2.4 效果混合postConcat
- 2.5 示例
- 3.使用颜色矩阵来改变图片
- 3.1几种图片颜色矩阵处理效果
- 3.1.1 灰度效果
- 3.1.2 图像颜色反转
- 3.1.3 怀旧效果
- 3.1.4 去色效果
- 3.1.5 高饱和度
- 4.像素点分析
- 4.1常用图像像素点处理效果
- 4.1.1 底片效果
- 4.1.2 浮雕效果
1.色彩矩阵
图片是由点阵和颜色值组成的,点阵是一个包含像素的举证,每个元素对应着图片的一个像素。当我知道颜色和矩阵有关时比较惊讶,大学时学的线性代数在这里用上了。
在Android中处理图像的色彩效果的类是颜色矩阵ColorMatrix。颜色矩阵是一个4x5的数字矩阵。对于每个像素点,都有一个颜色分量矩阵用来保存颜色的RGBA值。
A = { a b c d e f g h i j k l m n o p q r s t } C = { R G B A 1 } A= \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} C= \left\{ \begin{matrix} R \\ G \\ B \\ A \\ 1 \end{matrix} \right\} A=⎩⎪⎪⎨⎪⎪⎧afkpbglqchmrdinsejot⎭⎪⎪⎬⎪⎪⎫C=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧RGBA1⎭⎪⎪⎪⎪⎬⎪⎪⎪⎪⎫
矩阵A是一个4x5的颜色矩阵,在Android中使用一维数组的形式来存储[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]。矩阵C是一个颜色矩阵分量。
使用矩阵乘法运算AC来处理颜色分量矩阵,矩阵A、C,乘法运算过程,如下。
R = { R 1 G 1 B 1 A 1 } = A C { a b c d e f g h i j k l m n o p q r s t } { R G B A 1 } = { a R b G c B d A e f R g G h B i A j R k G l B m A n o R p G q B r A s t } = { R 1 G 1 B 1 A 1 } R =\left\{ \begin{matrix} R1\\G1 \\ B1 \\ A1 \end{matrix} \right\} =AC \\ \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} \left\{ \begin{matrix} R\\G \\ B \\ A \\1 \end{matrix} \right\} =\left\{ \begin{matrix} aR & bG & cB & dA & e\\ fR & gG & hB & iA & j \\ Rk & Gl & Bm & An & o \\ Rp & Gq & Br & As & t \end{matrix} \right\} =\left\{ \begin{matrix} R1\\G1 \\ B1 \\ A1 \end{matrix} \right\} R=⎩⎪⎪⎨⎪⎪⎧R1G1B1A1⎭⎪⎪⎬⎪⎪⎫=AC⎩⎪⎪⎨⎪⎪⎧afkpbglqchmrdinsejot⎭⎪⎪⎬⎪⎪⎫⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧RGBA1⎭⎪⎪⎪⎪⎬⎪⎪⎪⎪⎫=⎩⎪⎪⎨⎪⎪⎧aRfRRkRpbGgGGlGqcBhBBmBrdAiAAnAsejot⎭⎪⎪⎬⎪⎪⎫=⎩⎪⎪⎨⎪⎪⎧R1G1B1A1⎭⎪⎪⎬⎪⎪⎫
R1 = a x R + b x G + c x B + d x A + e;
G1 = f x R + g x G + h x B + i x A + j;
B1 = k x R + l x G + m x B + n x A +o;
A1 = p x R + q x G + r x B + s x A + t;
A = { a b c d e f g h i j k l m n o p q r s t } A= \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} A=⎩⎪⎪⎨⎪⎪⎧afkpbglqchmrdinsejot⎭⎪⎪⎬⎪⎪⎫
- 第一行的abcde值用来决定新的颜色值中的R——红色
- 第二行的fghij值用来决定新的颜色值中的G——绿色
- 第三行的klmno值用来决定新的颜色值中的B——蓝色
- 第四行的pqrst值用来决定新的颜色值中的A——透明色
第五列ejot值分别用来决定每个分量中的offset,即偏移量
R1 = a x R + b x G + c x B + d x A + e,令a=1,b、c、d、e都等于0,结果为R1 =R。构造一个矩阵,如下。
A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=⎩⎪⎪⎨⎪⎪⎧10000100001000010000⎭⎪⎪⎬⎪⎪⎫
如果把这个矩阵代入R1=AC,R1=R。这个矩阵通常被用来作为初始颜色矩阵来使用,不会对原有颜色值进行任何变化。
改变颜色的两种方法:一是直接改变颜色的offset,二是改变对应RGBA的系数。
1.1改变偏移量
A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A = { 1 0 0 0 100 0 1 0 0 100 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 100\\ 0 & 1 & 0 & 0 & 100 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=⎩⎪⎪⎨⎪⎪⎧10000100001000010000⎭⎪⎪⎬⎪⎪⎫A=⎩⎪⎪⎨⎪⎪⎧100001000010000110010000⎭⎪⎪⎬⎪⎪⎫
红色、绿色分量增加了100,红绿混合会得到黄色,最后图片颜色偏黄。
1.2改变颜色系数
A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A = { 1 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 2 & 0 & 0 & 0\\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=⎩⎪⎪⎨⎪⎪⎧10000100001000010000⎭⎪⎪⎬⎪⎪⎫A=⎩⎪⎪⎨⎪⎪⎧10000200001000010000⎭⎪⎪⎬⎪⎪⎫
改变的绿色,图片颜色偏绿,后面会有相应的展示。
2.使用ColorMatrix来改变图片的色光属性
2.1 色调
setRotate(int axis, float degrees),axis使用0、1、2来代表R、G、B三种颜色。degrees处理的值。
ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);
2.2 饱和度
setSaturation(float sat),当sat为0时,图片就变成黑白图片了。
ColorMatrix saturationMatrix = new ColorMatrix();saturationMatrix.setSaturation(saturation);
2.3 亮度
setScale(float rScale, float gScale, float bScale,float aScale),当三原色以相同比例进行混合时,就会显示出白色,系统正是使用这个原理来改变一个图像的亮度。当亮度为0时,图片就变为黑色了。
ColorMatrix lumMatrix = new ColorMatrix();lumMatrix.setScale(lum, lum, lum, 1);
2.4 效果混合postConcat
将上面三种ColorMatrix 叠加,需要通过ColorMatrix 的postConcat方法。
ColorMatrix imageMatrix = new ColorMatrix();imageMatrix.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);
2.5 示例
通过三个seekbar来控制图片效果的变化。
seekbar的监听事件
//MID_VALUE =127 seekbar最大值255
// float mHue = 0;
// float mStauration = 1.0f;
// float mLum = 1.0f; @Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {int id = seekBar.getId();switch (id) {case R.id.sb_1:mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;break;case R.id.sb_2:mStauration = progress * 1.0F / MID_VALUE;break;case R.id.sb_3:mLum = progress * 1.0F / MID_VALUE;break;}iv.setImageBitmap(handleImageEffect(bm, mHue, mStauration, mLum));}
设置图像矩阵的代码
public Bitmap handleImageEffect(Bitmap bm,float hue,float saturation,float lum) {Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bmp);Paint paint = new Paint();ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);ColorMatrix saturationMatrix = new ColorMatrix();saturationMatrix.setSaturation(saturation);ColorMatrix lumMatrix = new ColorMatrix();lumMatrix.setScale(lum, lum, lum, 1);ColorMatrix imageMatrix = new ColorMatrix();imageMatrix.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));canvas.drawBitmap(bm, 0, 0, paint);return bmp;}
设置好颜色矩阵后,需要使用paint类的setColorFilter方法,将imageMatrix构造的ColorMatrixColorFilter对象传递进去。
Android系统不允许直接修改原图,必须通过原图创建一个同样大小的Bitmap,并将原图绘制到新的bitmap中。直接修改原图会报错java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor。
3.使用颜色矩阵来改变图片
接下来我们通过直接修改矩阵中的值来改变图片的显示效果。
布局文件xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/mm_iv"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="2" /><GridLayoutandroid:id="@+id/mm_gl"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="3"android:columnCount="5"android:rowCount="4" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginEnd="10dp"android:orientation="horizontal"><Buttonandroid:id="@+id/mm_but_change"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="改变" /><Buttonandroid:id="@+id/mm_but_reset"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_weight="1"android:text="重置" /></LinearLayout></LinearLayout>
动态创建edittext,添加到gridlayout
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mmactivity);mm_but_change = findViewById(R.id.mm_but_change);mm_but_reset = findViewById(R.id.mm_but_reset);mm_iv = findViewById(R.id.mm_iv);mm_gl = findViewById(R.id.mm_gl);bm = BitmapFactory.decodeResource(getResources(), R.mipmap.dgdfg);mm_iv.setImageBitmap(bm);mm_gl.post(new Runnable() {@Overridepublic void run() {etWidth = mm_gl.getWidth() / 5;etHeight = mm_gl.getHeight() / 4;addEts();initMatrix();}});}/*** 添加edittext*/private void addEts() {for (int i = 0; i < ets.length; i++) {EditText editText = new EditText(this);editText.setGravity(Gravity.CENTER);ets[i] = editText;mm_gl.addView(editText, etWidth, etHeight);}}/*** 设置edittext的值*/private void initMatrix() {for (int i = 0; i < ets.length; i++) {if (i % 6 == 0) {ets[i].setText(1 + "");} else {ets[i].setText(0 + "");}}}
获得修改后的EditText值,将矩阵值设置给颜色矩阵。
private void getMatrix() {for (int i = 0; i < 20; i++) {colorM[i] = Float.valueOf(ets[i].getText().toString());}}private void setImageMatrix() {Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);ColorMatrix colorMatrix = new ColorMatrix();colorMatrix.set(colorM);Canvas canvas = new Canvas(bitmap);Paint paint = new Paint();paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));canvas.drawBitmap(bm, 0, 0, paint);mm_iv.setImageBitmap(bitmap);}
最后,设置点击事件,重置是将图片还原,改变是将现有的矩阵作用到图片。
mm_but_change.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getMatrix();setImageMatrix();}});mm_but_reset.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {initMatrix();getMatrix();setImageMatrix();}});
3.1几种图片颜色矩阵处理效果
3.1.1 灰度效果
{ 0.33 0.59 0.11 0 0 0.33 0.59 0.11 0 0 0.33 0.59 0.11 0 0 0 0 0 1 0 } \left\{ \begin{matrix} 0.33 & 0.59 & 0.11 & 0 & 0\\ 0.33 & 0.59 & 0.11 & 0 & 0 \\ 0.33 &0.59 & 0.11& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} ⎩⎪⎪⎨⎪⎪⎧0.330.330.3300.590.590.5900.110.110.11000010000⎭⎪⎪⎬⎪⎪⎫
3.1.2 图像颜色反转
{ − 1 0 0 1 1 0 − 1 0 1 1 0 0 − 1 1 1 0 0 0 1 0 } \left\{ \begin{matrix} -1 & 0 & 0 & 1 & 1\\ 0 & -1 & 0 & 1 & 1 \\ 0 &0 & -1& 1& 1 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} ⎩⎪⎪⎨⎪⎪⎧−10000−10000−1011111110⎭⎪⎪⎬⎪⎪⎫
3.1.3 怀旧效果
{ 0.393 0.769 0.189 0 0 0.349 0.686 0.168 0 0 0.272 0.534 0.131 0 0 0 0 0 1 0 } \left\{ \begin{matrix} 0.393 & 0.769 & 0.189 & 0 &0\\ 0.349 &0.686 & 0.168 & 0 & 0\\ 0.272 &0.534 & 0.131& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} ⎩⎪⎪⎨⎪⎪⎧0.3930.3490.27200.7690.6860.53400.1890.1680.131000010000⎭⎪⎪⎬⎪⎪⎫
3.1.4 去色效果
{ 1.5 1.5 1.5 0 − 1 1.5 1.5 1.5 0 − 1 1.5 1.5 1.5 0 − 1 0 0 0 1 0 } \left\{ \begin{matrix} 1.5 & 1.5 & 1.5 & 0 &-1\\ 1.5 &1.5 & 1.5 & 0 & -1\\ 1.5 &1.5 & 1.5& 0& -1 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} ⎩⎪⎪⎨⎪⎪⎧1.51.51.501.51.51.501.51.51.500001−1−1−10⎭⎪⎪⎬⎪⎪⎫
3.1.5 高饱和度
{ 1.438 − 0.112 − 0.016 0 − 0.03 − 0.062 1.378 − 0.016 0 0.05 − 0.062 − 0.122 1.483 0 − 0.02 0 0 0 1 0 } \left\{ \begin{matrix} 1.438 & -0.112 & -0.016 & 0 &-0.03\\ -0.062 &1.378 & -0.016 & 0 & 0.05\\ -0.062 &-0.122 & 1.483& 0& -0.02 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} ⎩⎪⎪⎨⎪⎪⎧1.438−0.062−0.0620−0.1121.378−0.1220−0.016−0.0161.48300001−0.030.05−0.020⎭⎪⎪⎬⎪⎪⎫
4.像素点分析
通过改变每个像素点argb值,来达到修改图片。android系统提供了Bitmap.getPixels()方法来获取这个bitmap的像素点。
bm.getPixels(int[] pixels, int offset, int stride,int x, int y, int width, int height)
pixels:接收每个点的颜色
offset:写入到pixels中的第一个像素索引值
stride:pixels中的行间距
x:从位图中读取的第一个像素的X坐标值
y:从位图中读取的第一个像素的y坐标值
width:从每一行中读取的像素宽度
height:读取的行数
一般使用
bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
具体代码
public Bitmap handleImagePixelsOldPhoto(Bitmap bm) {//由于不能修改原始图片,需要创建一个图片的副本bmp Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),Bitmap.Config.ARGB_8888);int width = bm.getWidth();int height = bm.getHeight();int color = 0;int r, g, b, a, r1, g1, b1;//初始化像素数组的大小int[] oldPx = new int[width * height];int[] newPx = new int[width * height];//获取像素点bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);for (int i = 0; i < width * height; i++) {color = oldPx[i];a = Color.alpha(color);r = Color.red(color);g = Color.green(color);b = Color.blue(color);//效果的公式,用来改变像素点的颜色r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);//最大值255if (r1 > 255) {r1 = 255;}if (g1 > 255) {g1 = 255;}if (b1 > 255) {b1 = 255;}newPx[i] = Color.argb(a, r1, g1, b1);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}
4.1常用图像像素点处理效果
4.1.1 底片效果
处理方法都是前辈们研究出来的,这里我们只是使用。贴出代码和效果图。
public static Bitmap handleImageNegative(Bitmap bm) {int width = bm.getWidth();int height = bm.getHeight();int color;int r, g, b, a;Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);int[] oldPx = new int[width * height];int[] newPx = new int[width * height];bm.getPixels(oldPx, 0, width, 0, 0, width, height);for (int i = 0; i < width * height; i++) {color = oldPx[i];r = Color.red(color);g = Color.green(color);b = Color.blue(color);a = Color.alpha(color);r = 255 - r;g = 255 - g;b = 255 - b;if (r > 255) {r = 255;} else if (r < 0) {r = 0;}if (g > 255) {g = 255;} else if (g < 0) {g = 0;}if (b > 255) {b = 255;} else if (b < 0) {b = 0;}newPx[i] = Color.argb(a, r, g, b);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}
4.1.2 浮雕效果
直接贴代码。
public static Bitmap handleImagePixelsRelief(Bitmap bm) {Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),Bitmap.Config.ARGB_8888);int width = bm.getWidth();int height = bm.getHeight();int color = 0, colorBefore = 0;int a, r, g, b;int r1, g1, b1;int[] oldPx = new int[width * height];int[] newPx = new int[width * height];bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);for (int i = 1; i < width * height; i++) {colorBefore = oldPx[i - 1];a = Color.alpha(colorBefore);r = Color.red(colorBefore);g = Color.green(colorBefore);b = Color.blue(colorBefore);color = oldPx[i];r1 = Color.red(color);g1 = Color.green(color);b1 = Color.blue(color);r = (r - r1 + 127);g = (g - g1 + 127);b = (b - b1 + 127);if (r > 255) {r = 255;}if (g > 255) {g = 255;}if (b > 255) {b = 255;}newPx[i] = Color.argb(a, r, g, b);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}
这篇关于Android学习笔记之ColorMatrix、图像处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!