Android图片特效处理(像素处理)
2015-11-04 12:15
771 查看
这篇博客将会通过对像素的RGB分量做一个处理,然后达到一些特效。并没有很高端大气的代码。也没用使用ImageFilter等一些库。多数参考了别人,大神勿喷。
首先看一下今天的效果图。
由于上传大小限制的关系,只有一小部分。当然,功能中除了光晕,其他都是实现了的。如果可以的话,我回上传到github上gif图。代码请在文末下载。那么接下来,我们就来看下如何实现这些。
再次声明,绝大多数是操作像素实现的。速度上可能会很慢。不过不要紧,要的是思想。
由于代码太多的原因,下面只会给出关键性代码,更多代码请前往github。
图片灰度化
灰度化原理:当前像素值=0.3r+0.59g+0.11b
灰度化我在这里用2中方法实现的。一种是操作ColorMatrix,另一种是颜色分量处理。代码如下
关于ColorMatrix,参考官方文档。
上面这个通过对颜色的 与,左移,右移来拿到颜色分量,当然,也有更简单的方法拿到分离,后面会说。
对亮度/饱和度/对比度的操作
这里的操作就会用到颜色矩阵,颜色矩阵,我并不会多说。如果感兴趣就取查看官方文档。这并不是重点
水印文字
就是在图片之上绘制文字,详情看代码。
怀旧效果的实现
原理:
R=0.393r+0.769g+0.189b
G=0.349r+0.686g+0.168b
B=0.272r+0.534g+0.131b
怀旧效果也可以通过颜色矩阵来实现,下面是通过颜色矩阵实现的部分代码
接下来我们看如何通过操作像素分量来实现
代码都很简单,而且相同部分很多,重点就在于颜色分量的处理,这个处理是根据原理 来的。
模糊效果
原理:周边像素平均值
高斯模糊原理:周边像素的加权平均值
1.通过RenderScript来实现模糊
2.操作像素RGB
这里我用了网上的一个FastBlur类,这个类实现了模糊并且做了优化。
锐化效果
原理:分别获取当前像素点和八个周围像素点的RGB值,先求出当前像素点的RGB值与八个像素点RGB值的和的平均数,再乘以相应的系数,然后在与当前像素点之和
这里利用拉普拉斯矩阵。
浮雕效果
原理:前一像素分量值-当前像素分量值+127
核心代码:
底片效果
原理:取当前RGB分量与255差值作为最终分量值
代码:
光照效果
原理,以指定点为中心,置顶光照半径,计算点到光照中心的距离,根据距离增加光照值
核心代码:
熔铸效果
原理:当前RGB分量*128然后对(其他2个分量之和+1)取整,并保留分量的修改
核心代码:
冰冻效果
原理:分量值 = (当前分量值-其他2个分量值的绝对值)*3/2;
核心代码:
雾化效果
原理:在图像中引入一定的随机值,打乱图像中的像素值
核心代码:
积木效果
原理:取3分量平均值,若大于128,则取255,否则取0 作为新分量值
核心代码:
连环画效果
原理:
R=|g-b+g+r|*r/256
G=|b-g+b+r|*r/256
B=|b-g+b+r|*g/256
核心代码
边缘高亮效果(霓虹处理)
原理:计算原像素的RGB分量与相同行(i+1)以及相同列(j+1)相邻像素的梯度,就是差的平方和的平方根,然后将梯度值作为处理后的像素
核心代码:
到这里就结束了,当然,图片处理特效还有很多,我这里仅仅是一小部分。在这里推荐一个库:ImageFilter
代码地址:github
参考资料:落日小屋
参考资料:其他原理
首先看一下今天的效果图。
由于上传大小限制的关系,只有一小部分。当然,功能中除了光晕,其他都是实现了的。如果可以的话,我回上传到github上gif图。代码请在文末下载。那么接下来,我们就来看下如何实现这些。
再次声明,绝大多数是操作像素实现的。速度上可能会很慢。不过不要紧,要的是思想。
由于代码太多的原因,下面只会给出关键性代码,更多代码请前往github。
图片灰度化
灰度化原理:当前像素值=0.3r+0.59g+0.11b
灰度化我在这里用2中方法实现的。一种是操作ColorMatrix,另一种是颜色分量处理。代码如下
public Bitmap doPro(Bitmap src) { int width,height; height = src.getHeight(); width = src.getWidth(); Bitmap bitmap = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setSaturation(0); ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix); paint.setColorFilter(filter); canvas.drawBitmap(src, 0, 0, paint); return bitmap; }
关于ColorMatrix,参考官方文档。
@Override public Bitmap doProByPix(Bitmap src) { int width = src.getWidth(); int height = src.getHeight(); //创建像素点数组 int[] pixels = new int[width*height]; int alpha,grey,red,green,blue; src.getPixels(pixels,0,width,0,0,width,height); alpha = 0xFF<<24; for (int i = 0 ; i < height ; i++){ for (int j = 0 ; j < width ; j++){ grey = pixels[width*i+j]; red = ((grey & 0x00FF0000)>>16); green = ((grey & 0x0000FF00)>>8); blue = ((grey & 0x000000FF)); grey = (int)((float)red*0.3+(float)green*0.59+(float)blue*0.11); grey = alpha | (grey<<16)|(grey<<8)|grey; pixels[width*i+j]=grey; } } Bitmap pro = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); pro.setPixels(pixels,0,width,0,0,width,height); return pro; }
上面这个通过对颜色的 与,左移,右移来拿到颜色分量,当然,也有更简单的方法拿到分离,后面会说。
对亮度/饱和度/对比度的操作
这里的操作就会用到颜色矩阵,颜色矩阵,我并不会多说。如果感兴趣就取查看官方文档。这并不是重点
public Bitmap doPro(Bitmap src) { int width = src.getWidth(); int height = src.getHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); ColorMatrix colorMatrix = new ColorMatrix(); //设置饱和度 设置为0.7 范围 0 - 1 //colorMatrix.setSaturation((float) 0.7); //设置亮度 colorMatrix.set(new float[]{1,0,0,0,70, 0,1,0,0,70, 0,0,1,0,70, 0,0,0,1,0}); //改变对比度 // colorMatrix.set(new float[]{2, 0, 0, 0, 0, // 0, 2, 0, 0, 0, // 0, 0, 2, 0, 0, // 0, 0, 0, 1, 0}); Paint paint = new Paint(); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src,0,0,paint); return bitmap; }
水印文字
就是在图片之上绘制文字,详情看代码。
怀旧效果的实现
原理:
R=0.393r+0.769g+0.189b
G=0.349r+0.686g+0.168b
B=0.272r+0.534g+0.131b
怀旧效果也可以通过颜色矩阵来实现,下面是通过颜色矩阵实现的部分代码
colorMatrix.set(new float[]{ (float) 0.393, (float) 0.768, (float) 0.189, 0, 0, (float) 0.349, (float) 0.686, (float) 0.168, 0, 0, (float) 0.272, (float) 0.534, (float) 0.131, 0, 0, 0, 0, 0, 1, 0 });
接下来我们看如何通过操作像素分量来实现
public Bitmap doProByPix(Bitmap src) { /** * 怀旧效果原理 * R=0.393r+0.769g+0.189b * G=0.349r+0.686g+0.168b * B=0.272r+0.534g+0.131b */ long startTime = System.currentTimeMillis(); int width = src.getWidth(); int height = src.getHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); int pixColor,pixR,pixG,pixB,newR,newG,newB; int[] pixels= new int[width*height]; src.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { //获取对应点的像素 pixColor = pixels[width*i+j]; pixR = Color.red(pixColor); pixG = Color.green(pixColor); pixB = Color.blue(pixColor); newR = (int) (0.393 * pixR + 0.769 * pixG + 0.189 * pixB); newG = (int) (0.349 * pixR + 0.686 * pixG + 0.168 * pixB); newB = (int) (0.272 * pixR + 0.534 * pixG + 0.131 * pixB); int newColor = Color.argb(255,Math.min(255,newR),Math.min(255,newG),Math.min(255, newB)); pixels[width*i+j]=newColor; } } bitmap.setPixels(pixels,0,width,0,0,width,height); long endTime = System.currentTimeMillis(); Log.e("tag","this is old used time "+(endTime-startTime)+"ms"); return bitmap; }
代码都很简单,而且相同部分很多,重点就在于颜色分量的处理,这个处理是根据原理 来的。
模糊效果
原理:周边像素平均值
高斯模糊原理:周边像素的加权平均值
1.通过RenderScript来实现模糊
public Bitmap RSblur(Bitmap src){ long startTime = System.currentTimeMillis(); Bitmap bitmap = Bitmap.createBitmap(src.getWidth(),src.getHeight(), Bitmap.Config.ARGB_8888); RenderScript renderScript = RenderScript.create(MyApplication.app); ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); Allocation allIn = Allocation.createFromBitmap(renderScript, src); Allocation allOut = Allocation.createFromBitmap(renderScript,bitmap); // 控制模糊程度 scriptIntrinsicBlur.setRadius(2.f); scriptIntrinsicBlur.setInput(allIn); scriptIntrinsicBlur.forEach(allOut); allOut.copyTo(bitmap); src.recycle(); renderScript.destroy(); long endTime = System.currentTimeMillis(); Log.e("tag","this is RenderScript blur use time "+(endTime-startTime)+"ms"); return bitmap; }
2.操作像素RGB
这里我用了网上的一个FastBlur类,这个类实现了模糊并且做了优化。
锐化效果
原理:分别获取当前像素点和八个周围像素点的RGB值,先求出当前像素点的RGB值与八个像素点RGB值的和的平均数,再乘以相应的系数,然后在与当前像素点之和
pixColor = pixels[(i + n) * width + k + m]; pixR = Color.red(pixColor); pixG = Color.green(pixColor); pixB = Color.blue(pixColor); newR = newR + (int) (pixR * laplacian[idx] * alpha); newG = newG + (int) (pixG * laplacian[idx] * alpha); newB = newB + (int) (pixB * laplacian[idx] * alpha); idx++;
这里利用拉普拉斯矩阵。
浮雕效果
原理:前一像素分量值-当前像素分量值+127
核心代码:
oldColor=oldPixels[i-1]; oldPixR = Color.red(oldColor); oldPixG = Color.green(oldColor); oldPixB = Color.blue(oldColor); newColor = newPixels[i]; newPixR = Color.red(newColor); newPixG = Color.green(newColor); newPixB = Color.blue(newColor); //计算 newPixR = (oldPixR-newPixR +127)>255?255:(oldPixR-newPixR +127) ; newPixG = (oldPixG -newPixG+127)>255?255:(oldPixG -newPixG+127) ; newPixB = (oldPixB-newPixB+127)>255?255:(oldPixB-newPixB+127);
底片效果
原理:取当前RGB分量与255差值作为最终分量值
代码:
color = piexls[i]; pixR = 255 - Color.red(color); pixG = 255 - Color.green(color); pixB = 255 - Color.blue(color);
光照效果
原理,以指定点为中心,置顶光照半径,计算点到光照中心的距离,根据距离增加光照值
核心代码:
color = pixels[j*width+i]; pixR= Color.red(color); pixG= Color.green(color); pixB = Color.blue(color); int distance = (int) (Math.pow((centerY-j),2)+Math.pow((centerX-i),2)); if (distance<radius*radius); { //按照距离大小计算增强的光照值 int result = (int) (strength*(1.0-Math.sqrt(distance)/radius)); pixR = pixR+result; pixG = pixG+result; pixB = pixB+result; } //做左右限制 pixR = Math.min(255,Math.max(0,pixR)); pixG = Math.min(255,Math.max(0,pixG)); pixB = Math.min(255,Math.max(0,pixB));
熔铸效果
原理:当前RGB分量*128然后对(其他2个分量之和+1)取整,并保留分量的修改
核心代码:
color=pixels[i]; pixR = Color.red(color); pixG = Color.green(color); pixB = Color.blue(color); //R 分量 pixR = pixR * 128/(pixG+pixB+1); pixR = Math.min(255,Math.max(0,pixR)); //G 分量 pixG = pixG*128/(pixB+pixR+1); pixG =Math.min(255,Math.max(0,pixG)); //B 分量 pixB = pixB*128/(pixR+pixG+1); pixB = Math.min(255,Math.max(0,pixB));
冰冻效果
原理:分量值 = (当前分量值-其他2个分量值的绝对值)*3/2;
核心代码:
color = pixels[i]; pixR = Color.red(color); pixG = Color.green(color); pixB = Color.blue(color); pixR = Math.abs((pixR - pixG - pixB) * 3 / 2); pixR = Math.min(255, pixR); pixG = Math.abs((pixG - pixR - pixB) * 3 / 2); pixG = Math.min(255, pixG); pixB = Math.abs((pixB - pixR - pixG) * 3 / 2); pixB = Math.min(255,pixB);
雾化效果
原理:在图像中引入一定的随机值,打乱图像中的像素值
核心代码:
k = random.nextInt(123456); int dx = i+k%8; int dy = j+k%8; if (dx>=width){ dx=width-1; } if (dy>=height){ dy=height-1; } pos = dy*width +dx; pos1 = j*width+i; pixels[pos1]=pixels[pos];
积木效果
原理:取3分量平均值,若大于128,则取255,否则取0 作为新分量值
核心代码:
color = pixels[i]; sum = (Color.red(color)+Color.blue(color)+Color.green(color))/3; if (sum>=128){ sum = 255; }else{ sum = 0; } pixels[i]=Color.argb(Color.alpha(color),sum,sum,sum);
连环画效果
原理:
R=|g-b+g+r|*r/256
G=|b-g+b+r|*r/256
B=|b-g+b+r|*g/256
核心代码
color=pixels[i]; pixR= Color.red(color); pixG = Color.green(color); pixB = Color.blue(color); //r pixR = Math.abs(pixG-pixB+pixG+pixR) * pixR /256; if (pixR>255){ pixR = 255; } pixG =Math.abs(pixB-pixG+pixB+pixR) *pixR/256; if (pixG>255){ pixG = 255; } //B=|b-g+b+r|*g/256 pixB = Math.abs(pixB-pixG+pixB+pixR) * pixG/256; if (pixB>256){ pixB=255; }
边缘高亮效果(霓虹处理)
原理:计算原像素的RGB分量与相同行(i+1)以及相同列(j+1)相邻像素的梯度,就是差的平方和的平方根,然后将梯度值作为处理后的像素
核心代码:
color=pixels[j*width+i]; //获取i+1像素 color_right = pixels[j*width+i+1]; //获取j+1像素 color_bottom = pixels[(j+1)*width+i]; //计算R分量 pixR = (int) (Math.pow((Color.red(color)-Color.red(color_right)),2) +Math.pow((Color.red(color)-Color.red(color_bottom)),2)); pixR = ((int) (Math.sqrt(pixR)*2)); pixR = Math.min(255,Math.max(0,pixR)); //计算G 分量 pixG = (int) (Math.pow((Color.green(color)-Color.green(color_right)),2) +Math.pow((Color.green(color)-Color.green(color_bottom)),2)); pixG = ((int) (Math.sqrt(pixG)*2)); pixG = Math.min(255,Math.max(0,pixG)); //计算B分量 pixB = (int) (Math.pow((Color.blue(color)-Color.blue(color_right)),2) +Math.pow((Color.blue(color)-Color.blue(color_bottom)),2)); pixB = ((int) (Math.sqrt(pixB)*2)); pixB = Math.min(255,Math.max(0,pixB)); pixels[j*width+i] = Color.argb(Color.alpha(color),pixR,pixG,pixB);
到这里就结束了,当然,图片处理特效还有很多,我这里仅仅是一小部分。在这里推荐一个库:ImageFilter
代码地址:github
参考资料:落日小屋
参考资料:其他原理
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories