利用色光三原色调整图片颜色

      最近学习了android中的图片颜色的处理,现在来总结一下。android中存在三种方式来调整图片的颜色,来达到不同的效果。分别是:利用色光三原色来调整图片颜色,利用颜色矩阵来调整图片颜色,利用调整每一个像素点来调整图片颜色。显然调整颜色的方式是越来越细致的。那么在这一篇文章中,就总结一下通过色光三原色来调整图片的颜色。

一、基础知识

     首先说一下基础的颜色知识。android中采取的颜色模型是RGBA模型。即R代表红色,G代表绿色,B代表蓝色,A代表透明度。而通过改变一张图片的三原色的色相,饱和度,亮度就可以改变一张图片的颜色。

     所谓色相,就是指具体的颜色,比如说红色,黄色等就是一种具体的颜色。而饱和度就是指颜色的纯度,值从0%到100%。亮度就是指颜色相对的明暗程度。只要改变这三个值,就可以实现不同的颜色效果。

       android中是通过ColorMatrix类来改变色光三原色的,从这个类就可以看出其实本质还是通过改变颜色矩阵来改变颜色的,只不过封装的好。所以颜色矩阵实现不同的颜色是基本的原理,在下一篇的文章中会讲到。下面就看一看要用到的方法,代码如下:

 1 //实例化处理色相的颜色矩阵
 2 ColorMatrix hugeMatrix = new ColorMatrix();
 3 hugeMatrix.setRotate(0, huge);//0表示红色
 4 hugeMatrix.setRotate(1, huge);//1表示设置绿色
 5 hugeMatrix.setRotate(2, huge);//2表示蓝色
 6         
 7 //实例化处理饱和度的矩阵
 8 ColorMatrix satMatrix = new ColorMatrix();
 9 //查看该方法的源码发现,只设置一个值方法内部就直接改变了每一个三原色的饱和度
10 satMatrix.setSaturation(saturation);
11         
12 //实例化处理亮度的矩阵
13 ColorMatrix lumMatrix = new ColorMatrix();
14 //参数从左到右依次为红色亮度,绿色,蓝色,透明度(1表示完全不透明)
15 lumMatrix.setScale(lum, lum, lum, 1);

      上面的代码注释很明白了,需要说明的事huge,saturation,lum都是float类型的值,为0-255之间。有了这些基础知识,我们就可以改变一张图片的颜色了。

       或许你还是很糊涂,虽然通过上面的代码,你知道怎么设置色光三原色的色相,饱和度和亮度,但是你还不知道怎么将设置好的颜色替换掉已有图片的颜色。那么就接着看下面的代码,下面的代码是一个实现图片颜色变化的工具类,该工具类中的静态方法实现了将一张图片变换颜色效果。具体思路就是传入一张图片,由于android不允许在已有的bitmap上操作,所以我们要新建一个bitmap,然后用设置好的颜色来设置画笔,接着用画笔画出一张和原来图片一样大小的bitmap,只是颜色变成了我们设置的颜色了而已,然后将该图片返回。好了,我们来看这个工具类的具体代码,注释很详细,你应该能看得懂。如下:

 1 /*
 2  * 用来处理图片颜色的工具类
 3  */
 4 public class ImageHelper {
 5     
 6     /**
 7      * 该方法根据色光三原色,改变图片颜色
 8      * @param bmp 原图片
 9      * @param huge 色相
10      * @param saturation 饱和度
11      * @param lum 亮度
12      * @return
13      */
14     public static Bitmap ImageUtil(Bitmap bmp,float huge,float saturation,float lum){
15         //注意,android不允许在原有的bitmap上操作,因此我们必须重画一个btimap来保存我们所做的操作并返回
16         //第三个参数为制定颜色模式,通常会使用bitmap的最高处理方式
17         Bitmap btp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
18         
19         Canvas canvas = new Canvas(btp);//实例化一块画布
20         Paint mPaint = new Paint();//实例化一支画笔
21         mPaint.setStrokeWidth(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿
22         
23         //实例化处理色相的颜色矩阵
24         ColorMatrix hugeMatrix = new ColorMatrix();
25         hugeMatrix.setRotate(0, huge);//0表示红色
26         hugeMatrix.setRotate(1, huge);//1表示设置绿色
27         hugeMatrix.setRotate(2, huge);//2表示蓝色
28         
29         //实例化处理饱和度的矩阵
30         ColorMatrix satMatrix = new ColorMatrix();
31         //查看该方法的源码发现,只设置一个值方法内部就直接改变了每一个三原色的饱和度
32         satMatrix.setSaturation(saturation);
33         
34         //实例化处理亮度的矩阵
35         ColorMatrix lumMatrix = new ColorMatrix();
36         //参数从左到右依次为红色亮度,绿色,蓝色,透明度(1表示完全不透明)
37         lumMatrix.setScale(lum, lum, lum, 1);
38         
39         //再实例化一个颜色矩阵将上面的颜色设定都柔和再一起
40         ColorMatrix imageMatrix = new ColorMatrix();
41         imageMatrix.postConcat(hugeMatrix);
42         imageMatrix.postConcat(satMatrix);
43         imageMatrix.postConcat(lumMatrix);
44         
45         //将调好的颜色设置给画笔
46         mPaint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
47         //然后我们用调整好的颜色画笔将原来的图片bmp画到新的bitmap上
48         canvas.drawBitmap(bmp, 0, 0, mPaint);
49         
50         return btp;
51         
52     }
53 }

      有了这个工具类,我们就可以真的为一张图片来变化其颜色了。下面我们来实战一下吧。

二、实战演示图片颜色变化

      我们废话少说,直接来写代码。新建项目”图像处理“,首先编写它的activity_main.xml。代码很简单,无非就是给按钮注册一个点击事件。我就不解释了,如下:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:gravity="center">
 6 
 7     <TextView
 8         android:id="@+id/txt_img"
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content"
11         android:text="图像实验" 
12         android:textSize="30sp"
13         android:gravity="center"
14         android:background="#cc00ff"/>
15     <Button 
16         android:id="@+id/bnt_imgcolor1"
17          android:layout_width="match_parent"
18         android:layout_height="wrap_content"
19         android:text="调整三原色" 
20         android:textSize="30sp"
21         android:gravity="center"
22         android:layout_below="@id/txt_img"
23         android:onClick="preferenceClick"
24         />
25       <Button 
26         android:id="@+id/bnt_imgcolor2"
27          android:layout_width="match_parent"
28         android:layout_height="wrap_content"
29         android:text="调整颜色矩阵" 
30         android:textSize="30sp"
31         android:gravity="center"
32         android:layout_below="@id/bnt_imgcolor1"
33         android:onClick="matrixClick"
34         />
35        <Button 
36         android:id="@+id/bnt_imgcolor3"
37          android:layout_width="match_parent"
38         android:layout_height="wrap_content"
39         android:text="调整色素" 
40         android:textSize="30sp"
41         android:gravity="center"
42         android:layout_below="@id/bnt_imgcolor2"
43         android:onClick="pxClick"
44         />
45 
46 </RelativeLayout>

      你会发现有三个按钮,在这里,我们只实现第一个按钮”调整三原色“。其他两个按钮的实现,也就是颜色矩阵和像素点改变图片效果我们放在后面的两篇文章中讲解。

      然后我们再新建一个color1.xml,是用来显示图片用的,在这里需要一张图片,读者可以自行设定为自己的图片即可。代码如下:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     >
 6     <ImageView
 7         android:id="@+id/img"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:src="@drawable/test1">
11         </ImageView>
12     <SeekBar 
13         android:id="@+id/sbr_huge"
14         android:layout_width="match_parent"
15         android:layout_height="wrap_content"
16         android:layout_below="@id/img"/>
17      <SeekBar 
18         android:id="@+id/sbr_sat"
19         android:layout_width="match_parent"
20         android:layout_height="wrap_content"
21         android:layout_marginTop="30dp"
22         android:layout_below="@id/sbr_huge"/>
23      <SeekBar 
24         android:id="@+id/sbr_lum"
25         android:layout_width="match_parent"
26         android:layout_height="wrap_content"
27         android:layout_marginTop="30dp"
28         android:layout_below="@id/sbr_sat"/>
29    
30 
31 </RelativeLayout>

      好了,然后我们再新建一个活动”ColorAdjustActivity“,用来将这个布局显示出来,注意不要忘记注册这个活动哦!代码如下:

  1 package com.fuly.image;
  2 
  3 import android.app.Activity;
  4 import android.graphics.Bitmap;
  5 import android.graphics.BitmapFactory;
  6 import android.os.Bundle;
  7 import android.widget.ImageView;
  8 import android.widget.SeekBar;
  9 
 10 public class ColorAdjustActivity extends Activity implements SeekBar.OnSeekBarChangeListener{
 11     
 12     private ImageView img;
 13     private SeekBar sbrHuge;
 14     private SeekBar sbrSat;
 15     private SeekBar sbrLum;
 16     
 17     private static final int MAX_VALUE = 255;
 18     private static final int MIDDLE_VALUE = 127;
 19     
 20     private float huge;//色相
 21     private float sat;//饱和度
 22     private float lum;//亮度
 23     
 24     private Bitmap priBmp;//原始图片
 25     
 26 
 27     protected void onCreate(Bundle savedInstanceState) {
 28         super.onCreate(savedInstanceState);
 29         setContentView(R.layout.color1);
 30         
 31         img = (ImageView) findViewById(R.id.img);
 32         sbrHuge = (SeekBar) findViewById(R.id.sbr_huge);
 33         sbrSat = (SeekBar) findViewById(R.id.sbr_sat);
 34         sbrLum = (SeekBar) findViewById(R.id.sbr_lum);
 35         
 36         priBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test1);
 37         
 38         //注册监听器
 39         sbrHuge.setOnSeekBarChangeListener(this);
 40         sbrSat.setOnSeekBarChangeListener(this);
 41         sbrLum.setOnSeekBarChangeListener(this);
 42         
 43         sbrHuge.setMax(MAX_VALUE);//设定最大范围
 44         sbrSat.setMax(MAX_VALUE);
 45         sbrLum.setMax(MAX_VALUE);
 46         
 47         sbrHuge.setProgress(MIDDLE_VALUE);//设定初始停留位置
 48         sbrSat.setProgress(MIDDLE_VALUE);//设定初始停留位置
 49         sbrLum.setProgress(MIDDLE_VALUE);//设定初始停留位置
 50     }
 51 
 52 
 53 
 54     /**
 55      * 在该方法中我们监听每一个seekBar的状态改变
 56      * @param seekBar 我们点击的seekBar控件
 57      * @param progress  当前点击位置的值
 58      * @param fromUser
 59      */
 60     public void onProgressChanged(SeekBar seekBar, int progress,
 61             boolean fromUser) {
 62         
 63         switch(seekBar.getId()){
 64         
 65         case R.id.sbr_huge:
 66             //获得色相的计算公式
 67               huge = (progress - MIDDLE_VALUE) * 1.0F / MIDDLE_VALUE * 180;
 68             break;
 69         case R.id.sbr_sat:
 70             //获得饱和度的计算公式
 71             sat = progress*1.0f/MIDDLE_VALUE;
 72             break;
 73         case R.id.sbr_lum:
 74             //获得亮度的计算公式
 75             lum = progress*1.0f/MIDDLE_VALUE;
 76             break;
 77         }
 78         Bitmap bt = ImageHelper.ImageUtil(priBmp, huge, sat, lum);
 79         
 80         img.setImageBitmap(bt);//注意这一步,就实现了图片效果的改变
 81     }
 82 
 83 
 84 
 85     /**
 86      * 该方法在用户刚刚点击seeBar时被调用,一般在这里可以禁止用户对
 87      * seeBar的操作
 88      */
 89     public void onStartTrackingTouch(SeekBar seekBar) {
 90 
 91         
 92     }
 93 
 94 
 95 
 96     /**
 97      * 该方法在用户完成seeBar的操作时会被调用,一般来说,如果用户禁用了seekBar,
 98      * 则可能会在这个方法里重新启用seekBar
 99      * 
100      */
101     public void onStopTrackingTouch(SeekBar seekBar) {
102     
103         
104     }
105 
106 }

      上面的代码注释很清晰了,我就不多解释了。发现了没有,在78行,我们调用了处理图片颜色的工具类。所以我们要把这个工具类编写出来,其实就是上面基础知识的那个工具类。新建类”ImageHelper“,代码如下:

 1 package com.fuly.image;
 2 
 3 import android.graphics.Bitmap;
 4 import android.graphics.Canvas;
 5 import android.graphics.Color;
 6 import android.graphics.ColorMatrix;
 7 import android.graphics.ColorMatrixColorFilter;
 8 import android.graphics.Paint;
 9 
10 /*
11  * 用来处理图片颜色的工具类
12  */
13 public class ImageHelper {
14     
15     /**
16      * 该方法根据色光三原色,改变图片颜色
17      * @param bmp 原图片
18      * @param huge 色相
19      * @param saturation 饱和度
20      * @param lum 亮度
21      * @return
22      */
23     public static Bitmap ImageUtil(Bitmap bmp,float huge,float saturation,float lum){
24         //注意,android不允许在原有的bitmap上操作,因此我们必须重画一个btimap来保存我们所做的操作并返回
25         //第三个参数为制定颜色模式,通常会使用bitmap的最高处理方式
26         Bitmap btp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
27         
28         Canvas canvas = new Canvas(btp);//实例化一块画布
29         Paint mPaint = new Paint();//实例化一支画笔
30         mPaint.setStrokeWidth(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿
31         
32         //实例化处理色相的颜色矩阵
33         ColorMatrix hugeMatrix = new ColorMatrix();
34         hugeMatrix.setRotate(0, huge);//0表示红色
35         hugeMatrix.setRotate(1, huge);//1表示设置绿色
36         hugeMatrix.setRotate(2, huge);//2表示蓝色
37         
38         //实例化处理饱和度的矩阵
39         ColorMatrix satMatrix = new ColorMatrix();
40         //查看该方法的源码发现,只设置一个值方法内部就直接改变了每一个三原色的饱和度
41         satMatrix.setSaturation(saturation);
42         
43         //实例化处理亮度的矩阵
44         ColorMatrix lumMatrix = new ColorMatrix();
45         //参数从左到右依次为红色亮度,绿色,蓝色,透明度(1表示完全不透明)
46         lumMatrix.setScale(lum, lum, lum, 1);
47         
48         //再实例化一个颜色矩阵将上面的颜色设定都柔和再一起
49         ColorMatrix imageMatrix = new ColorMatrix();
50         imageMatrix.postConcat(hugeMatrix);
51         imageMatrix.postConcat(satMatrix);
52         imageMatrix.postConcat(lumMatrix);
53         
54         //将调好的颜色设置给画笔
55         mPaint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
56         //然后我们用调整好的颜色画笔将原来的图片bmp画到新的bitmap上
57         canvas.drawBitmap(bmp, 0, 0, mPaint);
58         
59         return btp;
60         
61     }
62 }

      代码就不用我多解释了吧。最后别忘记在MainActivity中实现活动的跳转,即点击”调整三原色“按钮,跳到图片显示界面。代码如下:

 1 package com.fuly.image;
 2 
 3 import android.os.Bundle;
 4 import android.view.View;
 5 import android.app.Activity;
 6 import android.content.Intent;
 7 
 8 public class MainActivity extends Activity {
 9     
10 
11   
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_main);
15     }
16 
17     /*
18      * btn1的点击事件
19      */
20       public void preferenceClick(View view){
21           
22           Intent intent = new Intent(this,ColorAdjustActivity.class);
23           startActivity(intent);
24           
25           
26       }

      好了,一切代码都完成了。我们赶紧运行,看看效果吧。左边为原图,右边为滑动seekBar时调整的效果。

                  

     滑动seekBar可以有不同的效果。如果你觉得还不过瘾,没关系。可以看我的下一篇文章《利用颜色矩阵实现图片效果》。但是请注意,在本篇实战中的代码要保存,因为在下一节中,我们仍旧要在这个基础上写代码。

     对了,还需要总结一下,在设置色相,饱和度和亮度时,我们用到了三个公式,即下面的代码:

//获得色相的计算公式
 huge = (progress - MIDDLE_VALUE) * 1.0F / MIDDLE_VALUE * 180;
        
//获得饱和度的计算公式
sat = progress*1.0f/MIDDLE_VALUE;
            
//获得亮度的计算公式
um = progress*1.0f/MIDDLE_VALUE;

     其中progress是一个float的数值(0~255),MIDDLE_VALUE的值是127。这三个公式希望能记住,这是前辈们根据经验得到的。

原文地址:https://www.cnblogs.com/fuly550871915/p/4883422.html