Android中有两个比较重要的矩阵,ColorMatrix和Matrix。ColorMatrix用来改变bitmap的颜色和透明度,Matrix用来对bitmap平移、缩放、错切。对矩阵的概念不理解可参考:https://zh.wikipedia.org/wiki/%E7%9F%A9%E9%98%B5#%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95

【ColorMatrix(色彩矩阵)】

Android中Bitmap色彩用了一个[R, G, B, A],4*1的矩阵来保存。

如果想改变一个Bitmap的色彩该怎么办?现在来了解下ColorMatrix的相关知识。ColorMatrix 是一个4*5的矩阵。

我们用[R’, G’, B’, A’]来保存新的bitmap色彩,4*5必须和5*1矩阵相乘才能得到4*1矩阵,于是运算关系如下:

根据矩阵乘法通过如下运算,便能如下求出一个新的色彩矩阵了。

为什么要使用4*5矩阵而不是4*4矩阵?。因为只有4*5矩阵可以单独改变一种颜色值。比如你改变e,只会影响R’。

ColorMatrix的默认矩阵如下图所示

可以看出,进行色彩变换运算后色彩值仍然不变。

知道ColorMatrix的运算原理后,我们就可以做很多事情了。

【黑白图片】

黑白图片的去色原理:只要把RGB三通道的色彩信息设置成一样;即:R=G=B,那么图像就变成了灰色,并且,为了保证图像亮度不变,同一个通道中的R+G+B应该接近1。
在matlab中按照 0.2989 R,0.5870 G 和 0.1140 B 的比例构成像素灰度值。
在OpenCV中按照 0.299 R, 0.587 G 和 0.114 B 的比例构成像素灰度值。
在Android中按照0.213 R,0.715 G 和 0.072 B 的比例构成像素灰度值。
这些比例主要是根据人眼中三种不同的感光细胞的感光强度比例分配的,因此并没有一个确切值,不同工具调试出来的效果也不尽相同。

知道了RGB相关配色后,相关核心代码如下。

private Bitmap handleColorMatrix(){
Canvas canvas = new Canvas(mTempBmp); // 创建一个画布
Paint paint = new Paint(); // 新建paint
paint.setAntiAlias(true); //抗锯齿
//黑白
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0, 0, 0, 1, 0,
});
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));// 设置颜色变换效果
canvas.drawBitmap(mOriginBmp, 0, 0, paint);
return mTempBmp;
}

运行测试效果如下:

【色彩偏移与缩放】

我们可以通过增加最后一列的值来相应增加或减少某种颜色的值。

也可以通过改变对角线上的比例来进行色彩缩放。
比如给红色增加20.

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 20,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});

给绿色扩大到1.2倍。

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1.2f, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});

此外ColorMatrix提供了一个 setScale 来进行色彩缩放。

  /**
* Set this colormatrix to scale by the specified values.
*/
public void setScale(float rScale, float gScale, float bScale,
float aScale) {
final float[] a = mArray; for (int i = 19; i > 0; --i) {
a[i] = 0;
}
a[0] = rScale;
a[6] = gScale;
a[12] = bScale;
a[18] = aScale;
}

【色彩饱和度】

ColorMatrix提供了一个 setSaturation 通过改变对角线上的比例来改变饱和度。

/**
* Set the matrix to affect the saturation of colors.
*
* @param sat 饱和度的值,取值0,1
*/
public void setSaturation(float sat) {
reset();
float[] m = mArray; final float invSat = 1 - sat;
final float R = 0.213f * invSat;
final float G = 0.715f * invSat;
final float B = 0.072f * invSat; m[0] = R + sat; m[1] = G; m[2] = B;
m[5] = R; m[6] = G + sat; m[7] = B;
m[10] = R; m[11] = G; m[12] = B + sat;
}

可以看出,当sat取值为0时,即是黑白图片。

【色彩旋转】

看到旋转一词,可能有点蒙,何为色彩旋转?我们可以将RGB看做是一个坐标系(r,g,b)。
那么坐标系如下。

所以,我们可以把一个色彩值看成三维空间里的一个点,色彩值的三个分量可以看成该点的坐标(三维坐标)。假如,我们现在需要围绕蓝色轴进行旋转,我们对着蓝色箭头观察由红色和绿色构造的平面。然后顺时针旋转α度。

在图中,我们可以看到,在旋转后,原R在R轴的分量变为:R*cosα,且原G分量在旋转后在R轴上也有了分量,所以我们要加上这部分分量,因此最终的结果为R’=R*cosα+G*sinα,同理,在计算G’时,因为R的分量落在了负轴上,所以我们要减去这部分,故G’=G*cosα-R*sinα;
于是,我们可以求出矩阵如下。

同理,围绕红色轴旋转的矩阵如下。

围绕绿色轴旋转的矩阵如下。

同样,ColorMatrix提供了一个 setRotate(int axis, float degrees) 来进行色彩旋转。

public void setRotate(int axis, float degrees) {
reset();
double radians = degrees * Math.PI / 180d;
float cosine = (float) Math.cos(radians);
float sine = (float) Math.sin(radians);
switch (axis) { case 0: // 围绕红色轴旋转
mArray[6] = mArray[12] = cosine;
mArray[7] = sine;
mArray[11] = -sine;
break; case 1: // 围绕绿色轴旋转
mArray[0] = mArray[12] = cosine;
mArray[2] = -sine;
mArray[10] = sine;
break; case 2: // 围绕蓝色色轴旋转
mArray[0] = mArray[6] = cosine;
mArray[1] = sine;
mArray[5] = -sine;
break;
default:
throw new RuntimeException();
}
}

参考代码:

package com.yongdaimi.android.ffapitest;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView; public class MatrixDemoActivity extends AppCompatActivity implements View.OnClickListener { private ImageView iv_display;
private Bitmap mOriginBitmap;
private Bitmap mTmpBitmap; private Button bt_change_color;
private Button bt_revert_color; @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_matrix_demo); iv_display = findViewById(R.id.iv_display);
bt_change_color = findViewById(R.id.bt_change_color);
bt_change_color.setOnClickListener(this);
bt_revert_color = findViewById(R.id.bt_revert_color);
bt_revert_color.setOnClickListener(this); mOriginBitmap = ((BitmapDrawable) iv_display.getDrawable()).getBitmap();
mTmpBitmap = Bitmap.createBitmap(mOriginBitmap.getWidth(), mOriginBitmap.getHeight(), Bitmap.Config.ARGB_8888);
} private Bitmap handleColorMatrix() {
Canvas canvas = new Canvas(mTmpBitmap);
Paint paint = new Paint();
paint.setAntiAlias(true); ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1.2f, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});
/*
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 20,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
});
*/
/*
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0, 0, 0, 1, 0
});
*/ paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(mOriginBitmap, 0, 0, paint);
return mTmpBitmap;
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_change_color:
handleColorMatrix();
iv_display.setImageBitmap(mTmpBitmap);
break;
case R.id.bt_revert_color:
iv_display.setImageBitmap(mOriginBitmap);
break;
default:
break;
}
} }

本文转自:

1. Android Matrix矩阵详解

android: android 中的ColorMatrix (转)的更多相关文章

  1. Android学习探索之Java 8 在Android 开发中的应用

    前言: Java 8推出已经将近2年多了,引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时减化了各种设计模式的实现方式,是Java有史以来最重要的更新.但是Android上, ...

  2. Stack Overflow 排错翻译 - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder

    Stack Overflow 排错翻译  - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder 转自:ht ...

  3. Google官方关于Android架构中MVP模式的示例续-DataBinding

    基于前面的TODO示例,使用Data Binding库来显示数据并绑定UI元素的响应动作. 这个示例并未严格遵循 Model-View-ViewModel 或 Model-View-Presenter ...

  4. android studio 中移除module和恢复module

    一.移除Android Studio中module 在Android Studio中想要删除某个module时,在Android Studio中选中module,右键发现没有delete,如图: An ...

  5. 如何在Android应用中引入外部网页

    在某些情况下,我们需要在Android应用中引入外部网页,这里记录一下如何操作(其实很简单^.^). 先介绍一下开发环境: 开发工具:Android Studio 1.5 SDK API版本:17 操 ...

  6. NDK笔记(二)-在Android Studio中使用ndk-build

    前面一篇我们接触了CMake,这一篇写写关于ndk-build的使用过程.刚刚用到,想到哪儿写哪儿. 环境背景 Android开发IDE版本:AndroidStudio 2.2以上版本(目前已经升级到 ...

  7. Android Studio中Button等控件的Text中字符串默认大写的解决方法

    初学Android的时候,在Android Studio中xml里面添加一个Button.EditText等控件后,它的Text总是会显示大写,即使你输入的字符串是小写也不行,控制字符串大小写的属性是 ...

  8. .Net程序员之不学Java做安卓开发:Android Studio中的即时调试窗口

    对学.Net的人来说,JAVA开发是一场噩梦. .net中的即时窗口,调试时直接在里面写代码,对程序中的各种方法/属性进行调用,很方便. Android Studio中找了好久,参考如下网址,也有类似 ...

  9. 如何将Eclipse中的项目迁移到Android Studio 中

    如何将Eclipse中的项目迁移到Android Studio 中 如果你之前有用Eclipse做过安卓开发,现在想要把Eclipse中的项目导入到Android Studio的环境中,那么首先要做的 ...

  10. 第三方侧滑菜单SlidingMenu在android studio中的使用

    南尘:每天进步一点点! 前面讲了官方的侧滑菜单DrawerLayout的使用,其实早在官方没有推出这个之前,就有很多第三方的jar包如SlidingMenu等,感谢开源的力量. SlidingMenu ...

随机推荐

  1. 记录下这几天使用 GitHub 碰到的问题

    1.在 GitHub 上为新项目创建一个库时,默认是不使能主页功能的 如果你想要使用 GitHub 的主页功能做一个博客或一份简历,需要人为设置一下.如下图: 制作简历,这里有一份更详细的参考:如何在 ...

  2. SpringBoot整合Mybatis完整详细版二:注册、登录、拦截器配置

    接着上个章节来,上章节搭建好框架,并且测试也在页面取到数据.接下来实现web端,实现前后端交互,在前台进行注册登录以及后端拦截器配置.实现简单的未登录拦截跳转到登录页面 上一节传送门:SpringBo ...

  3. Shell脚本笔记(五)Shell函数

    Shell函数 1.定义语法 标准写法: funciton funName () { order....... return n } 简化写法1: funciton funName { order.. ...

  4. DWM1000 长距离模块讨论

    蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛 正文: DWM1000 作为超宽室内带测距/定位的代表,官方给出的模块标准距离30-50m,而目前X宝上有很多 ...

  5. SpringMVC url匹配却404,SimpleUrlHandlerMapping不起作用

    代码如下: <mvc:default-servlet-handler/> <bean class="org.springframework.web.servlet.hand ...

  6. 要过年啦,用canvas做了个烟火效果

    声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 要过年了,过年想到的就是放烟火啦....于是就用canvas写了个放烟火的效果,鼠标点击也会产生烟火,不过不要产生太多烟火哦,一个烟火散出 ...

  7. ES6 对对象的扩展

    1.对象类别 普通对象:具有JavaScript对象的所有默认内部行为 特异对象: 具有某些与默认行为不符的内部行为 标准对象: ECMAScript 6 规范中新定义的对象,例如Array,Date ...

  8. HTML5 — 地理定位

    Geolocation:地理定位,获取当前浏览器所在的地理坐标信息(包括经度.纬度.海拔高度.移动速度),实现LBS应用(Location Based Service)——基于定位的服务,如订   餐 ...

  9. Linux命令第四篇

    作业四: 1)  新建目录/test/dir,属主为tom,数组为group1,/test目录的权限为777 # useradd tom [root@localhost /]# groupadd gr ...

  10. R12.2常用手册

    >>Related Information Sources这本书包含在Oracle电子商务套件文档库中.如果该指南将您引用到其他Oracle电子商务套件文档中,只使用这些指南的最新版本12 ...