在上一篇文章中,我们学习了通过颜色矩阵的变换来实现图片不同颜色效果。没读过的朋友可以点击下面的链接:

http://www.cnblogs.com/fuly550871915/p/4883681.html

       在本篇中,我们将实现更加好玩的效果,比如老照片效果,浮雕效果等。

 

一、基础知识

     其实每一张图片的一个像素点就是一个颜色值,它包含四个分量,分别是:红,绿,蓝,透明度。试想如果我们能够遍历一张图片的每一个像素点,然后提取出这四个分量,做相应的计算操作,然后再返回,是不是就实现颜色的改变。没错,通过像素点来改变颜色就是这个原理。

    比如我们常见的底片的效果,它是遍历图片所有的像素点后,对每一个像素点(比如B点)做了下面的计算的:

 

    那么你可能会问,这个公式是怎么得到呢?这是研究图像处理的专家给出的,只要这样子处理像素点,就会得到一个底片效果。我们不必管这个。也就是说只要我们知道公式,就可以实现不同的有意思的效果。顺便再说两种效果的公式吧。

    老照片的效果计算公式:

     浮雕效果(注意是前一个像素减去后一个像素再加上127,再赋给前一个):

      好了,就介绍这几种效果吧。你或许还有疑问,怎么遍历像素点,并取出分量呢?其实Bitmp类和Colro类已经给我们提供了这样子的方法。我们看下面的设置底片效果的方法,注释写的很详细,你想知道的都在注释中。如下:

 1 /**
 2      * 将图片转换为负片
 3      * @param bitmap 原来图片
 4      * @return 新图片
 5      */
 6     public static Bitmap ImgaeToNegative(Bitmap bitmap){
 7         //其实我们获得宽和高就是图片像素的宽和高
 8         //它们的乘积就是总共一张图片拥有的像素点数
 9         int width = bitmap.getWidth();
10         int height = bitmap.getHeight();
11         
12         Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
13         
14         int[] oldPx = new int[width*height];//用来存储旧的色素点的数组
15         int[] newPx = new int[width*height];//用来存储新的像素点的数组
16         int color;//用来存储原来颜色值
17         int r,g,b,a;//存储颜色的四个分量:红,绿,蓝,透明度
18         
19         //该方法用来将图片的像素写入到oldPx中,我们这样子设置,就会获取全部的像素点
20         //第一个参数为写入的数组,第二个参数为读取第一个的像素点的偏移量,一般设置为0
21         //第三个参数为写入时,多少个像素点作为一行,第三个和第四个参数为读取的起点坐标
22         //第五个参数表示读取的长度,第六个表示读取的高度
23         bitmap.getPixels(oldPx, 0, width, 0, 0, width, height);
24         //下面用循环来处理每一个像素点
25         for(int i =0;i<width*height;i++){
26             
27             color = oldPx[i];//获取一个原来的像素点
28             r = Color.red(color);//获取红色分量,下同
29             g = Color.green(color);
30             b = Color.blue(color);
31             a = Color.alpha(color);
32             
33             //下面计算生成新的颜色分量
34             r = 255 -r;
35             g = 255 - g;
36             b = 255 - b;
37             
38             //下面主要保证r g b 的值都必须在0~255之内
39             if(r>255){
40                 r = 255;
41             }else if(r<0){
42                 r = 0;
43             }
44             if(g>255){
45                 g = 255;
46             }else if(g<0){
47                 g = 0;
48             }
49             if(b>255){
50                 b = 255;
51             }else if(b<0){
52                 b = 0;
53             }
54             
55             //下面合成新的像素点,并添加到newPx中
56             color = Color.argb(a, r, g, b);
57             newPx[i] = color;
58         }
59         
60         //然后重要的一步,为bmp设置新颜色了,该方法中的参数意义与getPixels中的一样
61         //无非是将newPx写入到bmp中
62         bmp.setPixels(newPx, 0, width, 0, 0, width, height);
63         return bmp;
64     }

      从上面的代码中,你学会了如何遍历一个图片的像素点以及如何取出颜色分量和合成新的颜色。其他的将图片变为老照片和浮雕,都是类似的方法。就不多讲了。那么我们可以直接进入实战了。

 

二、实战

      好了,我们仍旧在上一篇文章的基础上写代码,下面实现第三个按钮”调整色素“。首先编写color.3xml,用来显示调整后的图片,如下:

 1 <LinearLayout 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:orientation="vertical">
 6  
 7  <LinearLayout 
 8      android:layout_width="match_parent"
 9      android:layout_height="0dp"
10      android:layout_weight="1"
11      android:orientation="horizontal">
12      <ImageView 
13          android:id="@+id/img1"
14          android:layout_width="0dp"
15          android:layout_height="match_parent"
16          android:layout_weight="1"/>
17       <ImageView 
18          android:id="@+id/img2"
19          android:layout_width="0dp"
20          android:layout_height="match_parent"
21          android:layout_weight="1"/>
22     
23  </LinearLayout>
24  
25  <LinearLayout 
26      android:layout_width="match_parent"
27      android:layout_height="0dp"
28      android:layout_weight="1"
29      android:orientation="horizontal">
30         <ImageView 
31          android:id="@+id/img3"
32          android:layout_width="0dp"
33         android:layout_height="match_parent"
34          android:layout_weight="1"/>
35       <ImageView 
36          android:id="@+id/img4"
37          android:layout_width="0dp"
38           android:layout_height="match_parent"
39          android:layout_weight="1"/>
40     
41     
42  </LinearLayout>
43  
44  
45    
46 
47 </LinearLayout>

      在这个布局中,我们放置了四个ImageView,用来显示原图,底片,老照片以及浮雕效果。

     然后要扩充我们的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     /**
 63      * 将图片转换为负片
 64      * @param bitmap 原来图片
 65      * @return 新图片
 66      */
 67     public static Bitmap ImgaeToNegative(Bitmap bitmap){
 68         //其实我们获得宽和高就是图片像素的宽和高
 69         //它们的乘积就是总共一张图片拥有的像素点数
 70         int width = bitmap.getWidth();
 71         int height = bitmap.getHeight();
 72         
 73         Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 74         
 75         int[] oldPx = new int[width*height];//用来存储旧的色素点的数组
 76         int[] newPx = new int[width*height];//用来存储新的像素点的数组
 77         int color;//用来存储原来颜色值
 78         int r,g,b,a;//存储颜色的四个分量:红,绿,蓝,透明度
 79         
 80         //该方法用来将图片的像素写入到oldPx中,我们这样子设置,就会获取全部的像素点
 81         //第一个参数为写入的数组,第二个参数为读取第一个的像素点的偏移量,一般设置为0
 82         //第三个参数为写入时,多少个像素点作为一行,第三个和第四个参数为读取的起点坐标
 83         //第五个参数表示读取的长度,第六个表示读取的高度
 84         bitmap.getPixels(oldPx, 0, width, 0, 0, width, height);
 85         //下面用循环来处理每一个像素点
 86         for(int i =0;i<width*height;i++){
 87             
 88             color = oldPx[i];//获取一个原来的像素点
 89             r = Color.red(color);//获取红色分量,下同
 90             g = Color.green(color);
 91             b = Color.blue(color);
 92             a = Color.alpha(color);
 93             
 94             //下面计算生成新的颜色分量
 95             r = 255 -r;
 96             g = 255 - g;
 97             b = 255 - b;
 98             
 99             //下面主要保证r g b 的值都必须在0~255之内
100             if(r>255){
101                 r = 255;
102             }else if(r<0){
103                 r = 0;
104             }
105             if(g>255){
106                 g = 255;
107             }else if(g<0){
108                 g = 0;
109             }
110             if(b>255){
111                 b = 255;
112             }else if(b<0){
113                 b = 0;
114             }
115             
116             //下面合成新的像素点,并添加到newPx中
117             color = Color.argb(a, r, g, b);
118             newPx[i] = color;
119         }
120         
121         //然后重要的一步,为bmp设置新颜色了,该方法中的参数意义与getPixels中的一样
122         //无非是将newPx写入到bmp中
123         bmp.setPixels(newPx, 0, width, 0, 0, width, height);
124         return bmp;
125     }
126     /**
127      * 将图片变成老照片
128      * @param bitmap 原来的图片
129      * @return 新图片(即老照片)
130      */
131     public static Bitmap ImgaeToOld(Bitmap bitmap){
132         
133         int width = bitmap.getWidth();
134         int height = bitmap.getHeight();
135         
136         Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
137         
138         int[] oldPx = new int[width*height];//用来存储旧的色素点的数组
139         int[] newPx = new int[width*height];//用来存储新的像素点的数组
140         int color;//用来存储原来颜色值
141         int r,g,b,a;//存储颜色的四个分量:红,绿,蓝,透明度
142         
143         //第一个参数为写入的数组,第二个参数为读取第一个的像素点的偏移量,一般设置为0
144         //第三个参数为写入时,多少个像素点作为一行,第三个和第四个参数为读取的起点坐标
145         //第五个参数表示读取的长度,第六个表示读取的高度
146         bitmap.getPixels(oldPx, 0, width, 0, 0, width, height);
147         
148         for(int i =0;i<width*height;i++){
149             
150             color = oldPx[i];//获取一个原来的像素点
151             r = Color.red(color);//获取红色分量,下同
152             g = Color.green(color);
153             b = Color.blue(color);
154             a = Color.alpha(color);
155             
156             //下面计算生成新的颜色分量
157             r = (int)(0.393*r+0.769*g+0.189*b);
158             g = (int)(0.349*r+0.686*g+0.168*b);
159             b = (int)(0.272*r+0.534*g+0.131*b);
160             
161             //下面主要保证r g b 的值都必须在0~255之内
162             if(r>255){
163                 r = 255;
164             }else if(r<0){
165                 r = 0;
166             }
167             if(g>255){
168                 g = 255;
169             }else if(g<0){
170                 g = 0;
171             }
172             if(b>255){
173                 b = 255;
174             }else if(b<0){
175                 b = 0;
176             }
177             
178             //下面合成新的像素点,并添加到newPx中
179             color = Color.argb(a, r, g, b);
180             newPx[i] = color;
181         }
182         
183         //然后重要的一步,为bmp设置新颜色了
184         bmp.setPixels(newPx, 0, width, 0, 0, width, height);
185         return bmp;
186     }
187     /**
188      * 将图片变成浮雕
189      * @param bitmap 旧照片
190      * @return 新照片
191      */
192     public static Bitmap ImgaeToRelief(Bitmap bitmap){
193         
194         int width = bitmap.getWidth();
195         int height = bitmap.getHeight();
196         
197         Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
198         
199         int[] oldPx = new int[width*height];//用来存储旧的色素点的数组
200         int[] newPx = new int[width*height];//用来存储新的像素点的数组
201         int color;//用来存储前一个颜色值
202         int r,g,b,a;//存储颜色的四个分量:红,绿,蓝,透明度
203         int color1;//用来存储后一个颜色值
204         int r1,g1,b1,a1;
205         
206         //第一个参数为写入的数组,第二个参数为读取第一个的像素点的偏移量,一般设置为0
207         //第三个参数为写入时,多少个像素点作为一行,第三个和第四个参数为读取的起点坐标
208         //第五个参数表示读取的长度,第六个表示读取的高度
209         bitmap.getPixels(oldPx, 0, width, 0, 0, width, height);
210         //注意是从1开始循环
211         for(int i =1;i<width*height;i++){
212             
213             color = oldPx[i-1];//获取前一个像素点
214             r = Color.red(color);//获取红色分量,下同
215             g = Color.green(color);
216             b = Color.blue(color);
217             a = Color.alpha(color);
218             
219             color1 = oldPx[i];//获取后一个像素点
220             r1 = Color.red(color1);//获取红色分量,下同
221             g1 = Color.green(color1);
222             b1 = Color.blue(color1);
223             a1 = Color.alpha(color1);
224             
225             //下面计算生成新的颜色分量,注意浮雕是前一个像素减去后一个像素再加上127,赋给前一个
226             r = r - r1 + 127;
227             g = g - g1 + 127;
228             b = b - b1 +127;
229             
230             //下面主要保证r g b 的值都必须在0~255之内
231             if(r>255){
232                 r = 255;
233             }else if(r<0){
234                 r = 0;
235             }
236             if(g>255){
237                 g = 255;
238             }else if(g<0){
239                 g = 0;
240             }
241             if(b>255){
242                 b = 255;
243             }else if(b<0){
244                 b = 0;
245             }
246             
247             //下面合成新的像素点,并添加到newPx中
248             color = Color.argb(a, r, g, b);
249             newPx[i] = color;
250         }
251         
252         //然后重要的一步,为bmp设置新颜色了
253         bmp.setPixels(newPx, 0, width, 0, 0, width, height);
254         return bmp;
255     }
256     
257 }

        好了,我们所有的工具方法都有了,下面就编写”PxActivity“用来显示这些效果吧。代码如下:

 1 package com.fuly.image;
 2 
 3 import android.app.Activity;
 4 import android.graphics.Bitmap;
 5 import android.graphics.BitmapFactory;
 6 import android.graphics.drawable.BitmapDrawable;
 7 import android.os.Bundle;
 8 import android.widget.ImageView;
 9 
10 public class PxActivity extends Activity{
11     
12     private ImageView img1;
13     private ImageView img2;
14     private ImageView img3;
15     private ImageView img4;
16     
17     protected void onCreate(Bundle savedInstanceState) {
18         
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.color3);
21         img1 = (ImageView) findViewById(R.id.img1);
22         img2 = (ImageView) findViewById(R.id.img2);
23         img3 = (ImageView) findViewById(R.id.img3);
24         img4 = (ImageView) findViewById(R.id.img4);
25         
26         Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.test2);
27         
28         
29         img1.setImageBitmap(bmp);
30         img2.setImageBitmap(ImageHelper.ImgaeToNegative(bmp));
31         img3.setImageBitmap(ImageHelper.ImgaeToOld(bmp));
32         img4.setImageBitmap(ImageHelper.ImgaeToRelief(bmp));
33     }
34 
35 }

      代码很简单,无非就是调用我们的工具类设置图片而已。下面别忘记给这个活动注册,然后给MainActivity中的按钮注册监听,代码如下:

 1 package com.fuly.image;
 2 
 3 import android.os.Bundle;
 4 import android.view.View;
 5 import android.widget.Button;
 6 import android.app.Activity;
 7 import android.content.Intent;
 8 
 9 public class MainActivity extends Activity {
10     
11     private Button btn1;
12 
13   
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17         
18         btn1 = (Button) findViewById(R.id.bnt_imgcolor1);
19         
20     }
21 
22     /*
23      * btn1的点击事件
24      */
25       public void preferenceClick(View view){
26           
27           Intent intent = new Intent(this,ColorAdjustActivity.class);
28           startActivity(intent);
29           
30           
31       }
32       /*
33        * btn2的点击事件
34        */
35         public void matrixClick(View view){
36             
37             Intent intent = new Intent(this,ColorMatrixActivity.class);
38             startActivity(intent);
39            
40         }
41         /*
42          * btn3的点击事件
43          */
44           public void pxClick(View view){
45               
46               Intent intent = new Intent(this,PxActivity.class);
47               startActivity(intent);
48              
49           }
50 
51   
52 }

       好了,所有代码都完成了,运行程序,点击”调整色素“按钮,效果图如下:

         其实这个三个按钮都可以用了,我们可以随心所欲的实验,看看效果了。至此,android中的图像颜色处理就完结了,希望学习的的都能掌握。共同学习,一起进步!!

posted on 2015-10-15 21:37  fuly  阅读(3840)  评论(0编辑  收藏  举报