在上一篇文章中,咱们学习了经过颜色矩阵的变换来实现图片不一样颜色效果。没读过的朋友能够点击下面的连接:html
http://www.cnblogs.com/fuly550871915/p/4883681.htmlandroid
在本篇中,咱们将实现更加好玩的效果,好比老照片效果,浮雕效果等。canvas
1、基础知识数组
其实每一张图片的一个像素点就是一个颜色值,它包含四个份量,分别是:红,绿,蓝,透明度。试想若是咱们可以遍历一张图片的每个像素点,而后提取出这四个份量,作相应的计算操做,而后再返回,是否是就实现颜色的改变。没错,经过像素点来改变颜色就是这个原理。app
好比咱们常见的底片的效果,它是遍历图片全部的像素点后,对每个像素点(好比B点)作了下面的计算的:工具
那么你可能会问,这个公式是怎么获得呢?这是研究图像处理的专家给出的,只要这样子处理像素点,就会获得一个底片效果。咱们没必要管这个。也就是说只要咱们知道公式,就能够实现不一样的有意思的效果。顺便再说两种效果的公式吧。布局
老照片的效果计算公式:post
浮雕效果(注意是前一个像素减去后一个像素再加上127,再赋给前一个):学习
好了,就介绍这几种效果吧。你或许还有疑问,怎么遍历像素点,并取出份量呢?其实Bitmp类和Colro类已经给咱们提供了这样子的方法。咱们看下面的设置底片效果的方法,注释写的很详细,你想知道的都在注释中。以下:this
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 }
从上面的代码中,你学会了如何遍历一个图片的像素点以及如何取出颜色份量和合成新的颜色。其余的将图片变为老照片和浮雕,都是相似的方法。就很少讲了。那么咱们能够直接进入实战了。
2、实战
好了,咱们仍旧在上一篇文章的基础上写代码,下面实现第三个按钮”调整色素“。首先编写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中的图像颜色处理就完结了,但愿学习的的都能掌握。共同窗习,一块儿进步!!