颜色矩阵 滤镜 ColorMatrix
颜色矩阵原理
色彩的三要素1、色相。色相通俗的说就是“颜色”,色相的改变就是颜色的改变,色相的调节伴随着红橙黄绿蓝紫的变化。2、亮度。明度通俗的说就是“光照度”,明度的改变就是光照在物体上带来的改变,明度的调节伴随着越高,光越强,越泛白(就像过曝一样,往白色上偏离);越低,光越弱,越往黑里偏3、饱和度。饱和度通俗的说就是“色彩的纯度”,饱和度的改变会影响颜色的鲜艳程度,以红色为例子,越高,越接近红色,越低则越接近灰色(黑白)在编程中有时候需要对图片做特殊的处理,比如将图片做出黑白的,或者老照片的效果,有时候还要对图片进行变换,以拉伸,扭曲等等。
这些效果在android中有很好的支持,通过颜色矩阵 ColorMatrix 和坐标变换矩阵 Matrix 可以完美的做出上面的所说的效果。android中可以通过颜色矩阵 ColorMatrix 方便的操作颜色,颜色矩阵是一个5x4 的矩阵
第一行决定红色、第二行决定绿色、第三行决定蓝色、第四行决定了透明度。第五列是颜色的偏移量。
颜色矩阵以一维数组的方式存储如下:
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
他通过RGBA四个通道来直接操作对应颜色,如果会使用Photoshop就会知道有时处理图片通过控制RGBA各颜色通道来做出特殊的效果。而图像的RGBA值则存储在一个5*1的颜色分量矩阵C中,由颜色分量矩阵C可以控制图像的颜色效果![]()
要想改变一张图片的颜色效果,只需要改变图像的颜色分量矩阵即可。通过颜色矩阵可以很方便的修改图像的颜色分量矩阵。假设修改后的图像颜色分量矩阵为C1,则有如下图所示的颜色分量矩阵计算公式。矩阵的运算规则是:矩阵M的一行乘以矩阵C的一列作为矩阵R的一行。
M是颜色矩阵,C矩阵是图片中包含的RGBA信息,R矩阵是用M应用于C之后的新的颜色分量。由此可见,通过颜色矩阵修改了原图像的RGBA值,从而达到了改变图片颜色效果的目的。并且,通过上图所示的运算可知,颜色矩阵M的第一行参数abcde决定了图像的红色成分,第二行参数fghij决定了图像的绿色成分,第三行参数klmno决定了图像的蓝色成分,第四行参数pqrst决定了图像的透明度,第五列参数ejot是颜色的偏移量。通常,改变颜色分量时可以通过修改第5列的颜色偏移量来实现,如下图所示的颜色矩阵M1,通过计算后可以得知该颜色矩阵的作用是使图像的红色分量和绿色分量均增加100,这样的效果就是图片泛黄(因为红色与绿色混合后得到黄色)。除此之外,也可以通过直接对颜色值乘以某一系数而达到改变颜色分量的目的。如下图所示的颜色矩阵M2,将绿色分量放大了2倍,这样的效果就是图片泛绿色。
![]()
效果演示
调色器代码
public class MainActivity extends Activity implements OnSeekBarChangeListener, OnClickListener {private ImageView imageView;private SeekBar sb_red, sb_green, sb_blue, sb_brightness, sb_saturation;private Bitmap preBitmap, afterBitmap;private Canvas canvas;private ColorMatrix colorMatrix, rgbMatrix, huduMatrix;private Paint paint;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView = (ImageView) findViewById(R.id.iv);findViewById(R.id.btn_select).setOnClickListener(this);findViewById(R.id.btn_save).setOnClickListener(this);sb_red = (SeekBar) findViewById(R.id.sb_red);sb_green = (SeekBar) findViewById(R.id.sb_green);sb_blue = (SeekBar) findViewById(R.id.sb_blue);sb_brightness = (SeekBar) findViewById(R.id.sb_brightness);sb_saturation = (SeekBar) findViewById(R.id.sb_saturation);sb_red.setOnSeekBarChangeListener(this);sb_green.setOnSeekBarChangeListener(this);sb_blue.setOnSeekBarChangeListener(this);sb_brightness.setOnSeekBarChangeListener(this);sb_saturation.setOnSeekBarChangeListener(this);paint = new Paint();colorMatrix = new ColorMatrix();//5*4的颜色矩阵rgbMatrix = new ColorMatrix();//RGB颜色及亮度huduMatrix = new ColorMatrix();//饱和度或灰度}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {//进度改变时调用if (preBitmap != null) {float progressR = sb_red.getProgress() / 128f;//这里处理后值的范围为[0,2],初始值是1,也即初始时不做任何改变。float progressG = sb_green.getProgress() / 128f;float progressB = sb_blue.getProgress() / 128f;float progressA = sb_brightness.getProgress() / 128f;float progressS = sb_saturation.getProgress() / 128f;float[] values = new float[] { progressR, 0, 0, 0, 0,//0, progressG, 0, 0, 0,//0, 0, progressB, 0, 0,//0, 0, 0, progressA, 0 };////1、改变色相及亮度rgbMatrix.set(values);//2、改变饱和度、透明度、灰度。当饱和度=0时,会变成黑白图片(有灰度的黑白照片)。huduMatrix.setSaturation(progressS);//3、要想将色彩三元素综合运用到一张图片上,需要通过颜色矩阵的postConcat方法将三元素进行连接。colorMatrix.reset();//要重置一下才可以,不然等于是在之前的基础上进行的更改colorMatrix.postConcat(rgbMatrix);//这里其实是将两个矩阵进行了运算,熟悉矩阵运算的应该知道,先后顺序是有重大影响的colorMatrix.postConcat(huduMatrix);//4、通过颜色滤镜将颜色矩阵应用于图片上paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));canvas.drawBitmap(preBitmap, new Matrix(), paint);imageView.setImageBitmap(afterBitmap);} else Toast.makeText(getApplicationContext(), "清先选择一张图片再调整颜色", 0).show();}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//开始拖动时调用}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {//结束拖动时调用}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_select: // 激活系统图库,选择一张图片Intent intent = new Intent();intent.setAction(Intent.ACTION_PICK);intent.setType("image/*");startActivityForResult(intent, 0);break;case R.id.btn_save: //保存bitmap为图片File file = new File(Environment.getExternalStorageDirectory(), new SimpleDateFormat("yyyy.MM.dd HH-mm-ss", Locale.getDefault()).format(new Date()) + ".png");try {FileOutputStream out = new FileOutputStream(file);afterBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);out.close();} catch (Exception e) {Toast.makeText(this, "保存出现异常", Toast.LENGTH_SHORT).show();e.printStackTrace();}break;}}//返回一张照片后初始化afterBitmap@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (data != null && data.getData() != null) {try {Uri uri = data.getData();// 得到图片的全路径。相机目录下的某个文件的路径为:content://media/external/images/media/12718Log.i("bqt", "路径为:" + uri);//SD卡根目录下的文某个文件的件路径为:content://media/external/images/media/12758InputStream is = getContentResolver().openInputStream(uri);//获取文件的流preBitmap = BitmapFactory.decodeStream(is); //通过流加载图片} catch (FileNotFoundException e) {}// 创建一张可以被修改的空白图片afterBitmap = Bitmap.createBitmap(preBitmap.getWidth(), preBitmap.getHeight(), preBitmap.getConfig());canvas = new Canvas(afterBitmap);canvas.drawBitmap(preBitmap, new Matrix(), paint);//先把原图绘制上去,目的仅仅是让你预览一下imageView.setImageBitmap(afterBitmap);//注意imageView上显示的不是我们本地的图片,而是我们内存中刚刚new的Bitmap}super.onActivityResult(requestCode, resultCode, data);}}
调色器布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><SeekBarandroid:id="@+id/sb_red"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="255"android:progress="128" /><SeekBarandroid:id="@+id/sb_green"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="255"android:progress="128" /><SeekBarandroid:id="@+id/sb_blue"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="255"android:progress="128" /><SeekBarandroid:id="@+id/sb_brightness"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="255"android:progress="128" /><SeekBarandroid:id="@+id/sb_saturation"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="255"android:progress="128" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><Buttonandroid:id="@+id/btn_select"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="选择一张照片" /><Buttonandroid:id="@+id/btn_save"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="保存图片到SD卡" /></LinearLayout><ImageViewandroid:id="@+id/iv"android:layout_width="match_parent"android:layout_height="wrap_content" /></LinearLayout>
颜色矩阵演示
颜色矩阵代码
public class MainActivity extends Activity implements OnClickListener {private Paint myPaint;private Bitmap bitmap, alterBitmap;private Canvas canvas;private ColorMatrix myColorMatrix;private ImageView iv;private EditText[] editTextArray = new EditText[20];private float[] colorArray = new float[20];private int[] EditTextID = { R.id.Edit1, R.id.Edit2, R.id.Edit3, R.id.Edit4, R.id.Edit5, R.id.Edit6, R.id.Edit7, R.id.Edit8,R.id.Edit9, R.id.Edit10, R.id.Edit11, R.id.Edit12, R.id.Edit13, R.id.Edit14, R.id.Edit15, R.id.Edit16, R.id.Edit17,R.id.Edit18, R.id.Edit19, R.id.Edit20 };@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.Button).setOnClickListener(this);iv = (ImageView) findViewById(R.id.iv);for (int i = 0; i < 20; i++) {editTextArray[i] = (EditText) findViewById(EditTextID[i]);}myPaint = new Paint();myColorMatrix = new ColorMatrix();bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);iv.setImageBitmap(bitmap);//先用旧图装饰一下门面}@Overridepublic void onClick(View v) {for (int i = 0; i < 20; i++) {String num = editTextArray[i].getText().toString().trim();if (TextUtils.isEmpty(num)) colorArray[i] = 0;else colorArray[i] = Float.valueOf(num);}//每提交一次都要重新设置以下alterBitmap,不然等于是在上次的基础上修改了alterBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());canvas = new Canvas(alterBitmap);//必须先把原图画上去,然后才能通过颜色矩阵修改图片的颜色canvas.drawBitmap(bitmap, new Matrix(), new Paint());//注意这里的Paint不能直接使用myPaint,否则会重复绘制颜色滤镜。当然使用之前重置一下就可以用了。//设置颜色矩阵myColorMatrix.set(colorArray);myPaint.setColorFilter(new ColorMatrixColorFilter(myColorMatrix));canvas.drawBitmap(alterBitmap, 0, 0, myPaint);iv.setImageBitmap(alterBitmap);}}
颜色矩阵布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><ImageViewandroid:id="@+id/iv"android:layout_width="match_parent"android:layout_height="200dp"android:layout_gravity="center" /><Buttonandroid:id="@+id/Button"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="提交" /><LinearLayoutandroid:id="@+id/colorlayout1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><EditTextandroid:id="@+id/Edit1"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal"android:text="1" /><EditTextandroid:id="@+id/Edit2"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit3"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit4"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit5"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /></LinearLayout><LinearLayoutandroid:id="@+id/colorlayout2"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><EditTextandroid:id="@+id/Edit6"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit7"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal"android:text="1" /><EditTextandroid:id="@+id/Edit8"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit9"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit10"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /></LinearLayout><LinearLayoutandroid:id="@+id/colorlayout3"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><EditTextandroid:id="@+id/Edit11"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit12"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit13"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal"android:text="1" /><EditTextandroid:id="@+id/Edit14"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit15"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /></LinearLayout><LinearLayoutandroid:id="@+id/colorlayout4"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><EditTextandroid:id="@+id/Edit16"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit17"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit18"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /><EditTextandroid:id="@+id/Edit19"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal"android:text="1" /><EditTextandroid:id="@+id/Edit20"android:layout_width="50dp"android:layout_height="40dp"android:layout_weight="1"android:numeric="decimal" /></LinearLayout></LinearLayout>
颜色矩阵 滤镜 ColorMatrix的更多相关文章
- (转)android中颜色矩阵colormatrix
原文地址:http://www.cnblogs.com/menlsh/archive/2013/02/03/2890888.html 在Android中,对图像进行颜色方面的处理,如黑白老照片.泛黄旧 ...
- ColorMatrixFilter色彩矩阵滤镜;
包 flash.filters 类 public final class ColorMatrixFilter 继承 ColorMatrixFilter BitmapFilter Object 使用 ...
- Android学习笔记之图像颜色处理(ColorMatrix)
对图像进行颜色方面的处理,通过使用颜色矩阵(ColorMatrix)来实现.从而可以达到很多特效如黑白老照片.泛黄旧照片等等. 1.颜色矩阵(ColorMatrix) 这里有详细的介绍:http:// ...
- Egret中图片颜色的改变,颜色矩阵
参考: 图片处理:颜色矩阵和坐标变换矩阵 Egret-滤镜 之前面试有问到如何改变图片的颜色.貌似之前做Flash的时候做过,做Egret后没有此类需求,所以一直没有研究过. 现在来弄一弄如何改变图片 ...
- ColorMatrixFilter色彩矩阵滤镜
ColorMatrixFilter色彩矩阵滤镜: /** * * *----------------------------------------* * | *** ColorMatrixFilte ...
- ColorMatrixFilter色彩矩阵滤镜(as3)
matrix是一个长度为4*5=20的数组,其构成如下所示: R ,G, B, A, offset [1, 0, 0, 0, 0]); // red [0, 1, 0, 0, 0 ...
- AS3 滤镜相关
<ignore_js_op> package { import flash.display.Sprite; import flash.filters.BlurF ...
- Android ColorMatrix类图像颜色处理-黑白老照片、泛黄旧照片、高对比度等效果
在Android中,对图像进行颜色方面的处理,如黑白老照片.泛黄旧照片.高对比度.低饱和度等效果,都可以通过使用颜色矩阵(ColorMatrix)来实现. 1.颜色矩阵(ColorMatrix)介绍 ...
- Android图片处理(Matrix,ColorMatrix)
转发说明:原文链接http://www.cnblogs.com/leon19870907/articles/1978065.html 在编程中有时候需要对图片做特殊的处理,比如将图片做出黑白的,或者老 ...
随机推荐
- java 对list中对象按属性排序
实体对象类 --略 排序类----实现Comparator接口,重写compare方法 package com.tang.list; import java.util.Comparator; publ ...
- android 样式开发
1. Android的样式一般定义在res/values/styles.xml文件中,其中有一个根元素<resource>,而具体的每种样式定义则是通过<resource>下的 ...
- gtk程序如何进行编译
程序名: gtk_example.c 生成目标文件:gtk_example gcc gtk_example.c -o gtk_example `pkg-config --libs --cfl ...
- d017: 打印某年某月有几天
内容: 打印某年某月有几天 输入说明: 一行两个整数,前面是年份 后面是月份 输出说明: 一个整数 输入样例: 2009 6 输出样例 : 30 #include <stdio.h> ...
- js只能输入数字
$("#SeatCount, #Charge").on("keyup", function () { if (this.value.replace(/^0|\D ...
- 专门讲讲这个MYSQL授权当中的with grant option的作用
对象的owner将权限赋予某个用户(如:testuser1) grant select ,update on bd_corp to testuser1 [with grant option ]1.如果 ...
- Cracking the coding interview--Q1.2
原文 Implement a function void reverse(char* str) in C or C++ which reverses a null-terminated string. ...
- <item.../>元素可指定如下常用属性
android:id:为菜单项指定一个唯一表实.android:title:指定菜单项的标题.android:icon:指定菜单项的图标.android:alphabeticShortcut:为菜单项 ...
- HDU_2053
Problem Description There are many lamps in a line. All of them are off at first. A series of operat ...
- HDU-4857(拓扑排序)
Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前. ...