Android色彩特效处理之色调、饱和度、亮度、ColorMatrix精炼详解

您所在的位置:网站首页 屏幕亮度调整app Android色彩特效处理之色调、饱和度、亮度、ColorMatrix精炼详解

Android色彩特效处理之色调、饱和度、亮度、ColorMatrix精炼详解

2024-01-16 02:39| 来源: 网络整理| 查看: 265

一、前期基础知识储备

Bitmap(位图文件),扩展名可以是.bmp或者.dib。位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2、4、8、16、24和32位色彩。想象一下你以前测红绿色盲的时候,王医生拿给你看的那张红红绿绿小动物数字交通工具的图,那就是一个位图图片,由一个个像素组成。

    

一个位图图像的一个像素点,用RGBA四个值来描述,具体控制是通过一个4*5的矩阵来控制,每个像素点的RGBA又共同组成了位图的展现形式,这就意味着只要我们能控制像素点的RGBA值,就可以改变位图展示的效果。

基于此,Android中常用的对于图像色彩处理的常用方式有两种:

①使用ColorMatrix类来改变RGBA;

②使用专业的像素点算法来定点来改变RGBA。

二、上代码,具体实现通过ColorMatrix类进行色彩处理

我们需要知道在通常的色彩处理中,我们使用以下的专业词汇来描述一个图像:

色调——物体传播的颜色;

饱和度——颜色的纯度,从0(灰)到100%(饱和)来进行描述;

亮度——颜色的相对明暗程度;

在Android中,系统使用一个颜色矩阵——ColorMatrix,来处理图像的这些色彩效果。Android中的颜色矩阵是一个4×5的数字矩阵,它用来对图片的色彩进行处理。而对于每个像素点,都有一个颜色分量矩阵用来保存颜色的RGBA值,如下图所示:

在这个4×5的颜色矩阵中按以下方式划分:

第一行的abcde值用来决定新的颜色值中的R——红色

第二行的fghij值用来决定新的颜色值中的G——绿色

第三行的klmno值用来决定新的颜色值中的B——蓝色

第四行的pqrst值用来决定新的颜色值中的A——透明度

矩阵A中的第五列——ejot值分别用来决定每个分量重的offset,即偏移量。

1)色彩矩阵变化举例:

①改变偏移量

在这个矩阵中修改了R,G所对应的颜色偏移量,那么最后的处理结果就是图像的红色,绿色分量增加了100。而我们知道,红色混合绿色会得到黄色,所以使得整个图像的色调偏黄色。

②改变颜色系数

在这个矩阵中,改变了G分量所对应的系数g,这样的矩阵运算后G分量会变成以前的两倍,最终效果就是图像的色调更加偏绿。

2)使用ColorMatrix类来实现色彩处理:

图像的色调,饱和度,亮度这三个属性在图像处理中的使用非常多,因此颜色矩阵中,也封装了一些API来快速调用这些参数,而不用每次都去计算矩阵的值。

在Android中,系统封装了一个类——ColorMatrix,也就是说前面的颜色矩阵。通过这个类,可以很方便地改变矩阵值来处理颜色效果。官方文档中给出了三种ColorMatrix的构造方法:

ColorMatrix() Create a new colormatrix initialized to identity (as if reset() had been called). ColorMatrix(float[] src) Create a new colormatrix initialized with the specified array of values. ColorMatrix(ColorMatrix src) Create a new colormatrix initialized with the specified colormatrix. //通常情况下使用第一种即可,即ColorMatrix colorMatrix = new ColorMatrix();

①对于色调的处理,色调是传播出的颜色,所以RGB三个值都可以进行处理,Android系统提供了setRotate(int axis, float degree)来帮助我们设置颜色的色调。第一个参数,系统分别使用0、1、2来代表Red、Green、Blue三种颜色的处理;而第二个参数,就是需要处理的值,代码如下:

ColorMatrix hueMatrix = new ColorMatrix(); hueMatrix .setRotate(0,hue0); hueMatrix .setRotate(1,hue1); hueMatrix .setRotate(2,hue2);

②对于饱和度的处理,Android系统提供了setSaturation(float sat)方法来设置颜色的饱和度,参数代表设置颜色饱和度的值,当饱和度为0时,图像就变成灰度图像了,代码如下:

ColorMatrix saturationMatrix=new ColorMatrix(); saturationMatrix.setSaturation(saturation);

③对于亮度的处理,当三原色以相同的比例进行混合的时候,就会显示出白色,系统正式使用这个原理来改变一个图像的亮度的,代码如下,当亮度为0时,图像就变成全黑了,处理的代码如下:

ColorMatrix lumMatrix=new ColorMatrix(); lumMatrix.setScale(lum,lum,lum,1);

④色彩的混合处理,除了单独使用上面三种方式来进行颜色效果的处理之外,Android系统还封装了矩阵的乘法运算。它提供了postConcat()方法来将矩阵的作用效果混合,从而叠加处理效果,代码如下:

//将矩阵的作用效果混合,从而叠加处理效果 ColorMatrix imageMatrix=new ColorMatrix(); imageMatrix.posConcat(hueMatrix); imageMatrix.posConcat(saturationMatrix); imageMatrix.posConcat(lumMatrix); paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix)); canvas.drawBitmap(bitmap,0,0,paint);

最后通过paint.setColorFilter(newColorMatrixColorFilter(imageMatrix))设置给paint,并使用这个画笔来绘制原来的图像,从而将颜色矩阵作用到原图上,代码如下:

paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix)); canvas.drawBitmap(bitmap,0,0,paint);

下面给出《Android群英传》中通过SeekBar调整色彩的经典代码段:

public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener{ private static final int MAX_VALUE = 255; private static final int MID_VALUE = 127; private ImageView mImageView; private float mHue, mSaturation, mLum; private Bitmap mBitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.shuicai); mImageView = (ImageView) findViewById(R.id.imageview); SeekBar seekBarHue = (SeekBar) findViewById(R.id.seekbarHue); SeekBar seekBarSaturation = (SeekBar) findViewById(R.id.seekbarSaturation); SeekBar seekBarLum = (SeekBar) findViewById(R.id.seekbarLum); seekBarHue.setOnSeekBarChangeListener(this); seekBarSaturation.setOnSeekBarChangeListener(this); seekBarLum.setOnSeekBarChangeListener(this); //设置最大值 seekBarHue.setMax(MAX_VALUE); seekBarSaturation.setMax(MAX_VALUE); seekBarLum.setMax(MAX_VALUE); //设置进度 seekBarHue.setProgress(MID_VALUE); seekBarSaturation.setProgress(MID_VALUE); seekBarLum.setProgress(MID_VALUE); mImageView.setImageBitmap(mBitmap); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { switch (seekBar.getId()) { case R.id.seekbarHue://色调 mHue = (progress - MID_VALUE) * 1.0f / MID_VALUE * 180; break; case R.id.seekbarSaturation://饱和度 mSaturation = progress * 1.0f / MID_VALUE; break; case R.id.seekbarLum://亮度 mLum = progress * 1.0f / MID_VALUE; break; } mImageView.setImageBitmap(ImageHelper.handleImageEffect(mBitmap, mHue, mSaturation, mLum)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } } public class ImageHelper { public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation, float lum) { //设置颜色的色调 ColorMatrix hueMatrix = new ColorMatrix(); //第一个参数,系统分别使用0、1、2来代表Red、Green、Blue三种颜色的处理;而第二个参数,就是需要处理的值 hueMatrix.setRotate(0, hue); hueMatrix.setRotate(1, hue); hueMatrix.setRotate(2, hue); //设置颜色的饱和度 ColorMatrix saturationMatrix = new ColorMatrix(); //saturation参数即代表设置颜色的饱和度的值,当饱和度为0时,图像就变成灰度图像了 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()方法,将通过imageMatrix构造的 * ColorMatrixColorFilter对象传递进去,并使用这个画笔来绘制原来的图像,从而将颜色矩阵作用到原图中 */ Paint paint = new Paint(); paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix)); /** * Android系统也不允许直接修改原图,类似Photoshop中的锁定,必须通过原图创建一个同样大小的Bitmap,并将 * 原图绘制到该Bitmap中,以一个副本的形式来修改图像。 */ Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(bm, 0, 0 ,paint); return bitmap; } } 三、上代码,具体实现通过像素点算法进行色彩处理

作为更加精确的图像处理方式,可以通过改变每个像素点的具体RGBA值,来达到处理一张图像效果的目的。这里要注意的是传递进来的原始图片是不能修改的,一般根据原始图片生成一张新的图片来进行修改。

在Android中,系统提供了Bitmap.getPixels()方法来帮我们提取整个Bitmap中的像素点,并保存到一个数组中:

bitmap.getPixels(pixels,offset,stride,x,y,width,height);

这几个参数的含义如下:

pixels——接收位图颜色值的数组

offset——写入到pixels[]中的第一个像素索引值

stride——pixels[]中的行间距

x——从位图中读取的第一个像素的x坐标值

y——从位图中读取的第一个像素的y坐标值

width——从每一行中读取的像素宽度

height——读取的行数

通常情况下,可以使用如下代码:

bitmap.getPixels(oldPx,0,bm.getWidth(),0,0,width,height);

接下来就可以获取每个像素具体的ARGB了,如下:

color=oldPx[i]; r=Color.red(color); g=Color.green(color); b=Color.blue(color); a=Color.alpha(color);

当获取到具体的颜色值后,就可以通过相应的算法来修改它的ARGB值。如下老照片效果效果:

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);

再通过如下代码将新的RGBA值合成像素点:

newPx[i]=Color.argb(a,r1,g1,b1);

最后通过如下代码,将处理后的像素点数组重新set给我们的Bitmap,从而达到图像处理的目的:

bitmap.setPixels(newPx,0,width,0,0,width,height);

下面以《Android群英传》中底片效果为例,具体实现:

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;i255){ r=255; }else if(r255){ g=255; }else if(g255){ b=255; }else if(b


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3