Android对于图片的处理,最常用到的数据结构时位图------bitmap,它包含了一张图片所有的数据,整个图片都是由点阵和颜色组成的,所谓点阵就是一个包含像素的矩阵,每一个元素对应着图片的一个像素。而颜色值----ARGB,分别对应透明度、红、绿、蓝这四个通道分量,它们共同决定了每个像素点显示的颜色。

1.色彩矩阵分析

在色彩处理中,通常使用以下三个角度来描述一个图像。

  • 色调------物体传播的颜色
  • 饱和度------颜色的纯度,从0(灰)到100%(饱和)来进行描述
  • 亮度------颜色的相对明暗成都

而在Android中,系统使用一个颜色矩阵------ColorMatrix,来处理图像的这些色彩效果。Android中的颜色矩阵是一个4*5的颜色矩阵。在Android中,它会以一维数组的形式来存储[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t],而C则是一个颜色矩阵分量。在处理图像时,使用矩阵乘法运算AC来处理颜色分量矩阵,如下图所示。

根据前面对矩阵A、C的定义,通过矩阵乘法运算法则,可以得到如图所示的运算过程。

矩阵运算的乘法计算公式相信大家在线性代数课程中都学过,计算过程如下所示。

R1 = a*R + b*G + c*b +d*A + e
G1 = f*R + g*G + h*b +i*A + j
B1 = k*R + l*G + m*b +n*A + 0
A1 = p*R + q*G + r*b +s*A + t

从这个公式大家可以发现,对于上图中的4*5的颜色矩阵是按以下方式划分的。

  • 第一行的abcde值用来决定新的颜色值中的R------红色
  • 第二行的fghij值用来决定新的颜色值中的G------绿色
  • 第三行的klmno值用来决定新的颜色值中的B------蓝色
  • 第四行的pqrst值用来决定新的颜色值中的A------透明度
  • 矩阵A中的第5列----ejot值分别用来决定每个分量中的offset,即偏移量

这样划分好搁置的势力范围之后,这些值的作用就比较明确了。不过只这样说可能会比较抽象,下面我们通过几个小例子来进行进一步讲解。

首先重新看一下矩阵变换的计算公式,以R值为例。计算过程如下。

R1 = a*R + b*G + c*b +d*A + e

如果令a=1,b、c、d、e都等于0,那么计算结果为R1=R。因此可以构造出一个矩阵。如下图所示。

如果把这个矩阵带入公式R1=AC,那么根据矩阵乘法运算法则,可以得到R1=R。因此,这个矩阵通常被用来作为初始的颜色矩阵来使用,它不会对原有颜色值进行任何变化。

那么当我们要变换颜色值的时候,通常由两种方法,一个是直接改变颜色的offset,即偏移量的值来修改颜色分量,另一个方法是直接改变对应RGBA值的系数来调整颜色分量的值。

1.1改变偏移量

从前面的分析中,可以知道要修改R1的值,只要将第五列的值进行修改即可。即改变颜色的偏移量,其他值保持初始矩阵的值,如下图所示的颜色矩阵实现了这样的效果。

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

1.2改变颜色系数

如果修改颜色分量中的某个系数,而其他值依然保存初始矩阵的值,如下图。

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

1.3改变色光属性

图像的色调、饱和度、亮度这三个属性在图像处理中的使用非常之多。因此,在颜色矩阵中,也封装了一些API快速调整这些参数,而不用每次都去计算矩阵的值。下面通过一个实例来看看如何通过矩阵改变图像的色调、饱和度和亮度。

在Android中,系统封装了一个类------ColorMatrix,也就是前面所说的颜色矩阵。通过这个类,可以很方便的通过改变矩阵值来处理颜色效果。创建一个ColorMatrix对象非常简单,代码如下所示。

        ColorMatrix colorMatrix = new ColorMatrix();

下面我们来处理不同的色光属性。

  • 色调

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

通过这样的方法,可以为RGB三种颜色分量分别重新设置了不同的色调值。

  • 饱和度

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.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);

在了解了改变色光属性的原理之后,我们回到实现的例子中来。在本例中,通过滑动三个SeekBar来改变不同的数值,并将这些数值作用到对应的矩阵中。最后通过postConcat()方法来显示混合后的处理效果。

滑动SeekBar获取输入值的代码如下所示。

    @Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {switch (seekBar.getId()){case R.id.sb_hue:hue = (progress-MID_VALUE)/MID_VALUE *180;break;case R.id.sb_saturation:saturation = progress/MID_VALUE;break;case R.id.sb_hum:hum = progress/MID_VALUE;break;}imageView.setImageBitmap(ImageUtil.handleImageElefect(bitmap, hue,saturation,hum));}

设置图像矩阵的代码如下所示。

    public static Bitmap handleImageElefect(Bitmap bm, float hue, float saturation, float lum) {Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint paint = new Paint();ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);ColorMatrix saturationMatrix = new ColorMatrix();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(new ColorMatrixColorFilter(imageMatrix));canvas.drawBitmap(bm,0,0,paint);return bitmap;}

这里需要注意的时,再设置好的颜色矩阵后,通过使用Paint类的setColorFilter()方法,将通过imageMatrix构造的ColorMatrixColorFilter对象传递进去,并使用这个画笔来绘制原来的图像,从而将颜色矩阵作用到原图中。

同时,Android系统也不允许直接修改原图,类似Photoshop中的锁定,必须通过原图创建一个同样大小的Bitmap,并将原图绘制到该Bitmap中,以一个副本的形式来修改图像。代码如下所示,bm即为原图,bitmap为创建的副本。

        Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint paint = new Paint();canvas.drawBitmap(bm,0,0,paint);

运行程序后,显示效果如图所示。

当滑动三个代表色调、饱和度、亮度的SeekBar时,就可以实时地修改这幅图像的这三个属性了,运行效果如图所示。

       

2.Android颜色矩阵------ColorMatrix

通过前面的分析,我们知道了调整颜色矩阵可以改变一副图像的色彩效果,图像处理很大程度上就是再寻找处理图像的颜色矩阵。不仅仅可以通过Android系统提供的API来进行ColorMatrix的修改,同样可以精确的修改矩阵值来实现颜色效果的处理。

下面我们就模拟一个4*5的颜色矩阵。通过修改矩阵中的值,一来验证前面所说的改变图像色彩效果的原理是否正确;二来让读者朋友对矩阵变换产生的作用效果有更清晰的认识。

程序的难点在于创建下面的4*5的矩阵,通过GridLayout来进行布局,动态添加20个EditText,布局代码如下所示。

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.matrix_image);imageView = (ImageView)findViewById(R.id.iv);group = (GridLayout)findViewById(R.id.group);bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.iv);imageView.setImageBitmap(bitmap);group.post(new Runnable() {@Overridepublic void run() {mEtWidth = group.getWidth()/5;mEtHeight = group.getHeight()/4;addEts();initMatrix();}});}//添加EditTextprivate void addEts() {for (int i = 0; i < 20; i++) {EditText editText = new EditText(MainActivity2.this);mEts[i] = editText;group.addView(editText,mEtWidth,mEtHeight);}}//初始化颜色矩形为初始状态private void initMatrix() {for (int i = 0; i < 20; i++) {if ( i % 6 == 0 ) {mEts[i].setText("1");} else {mEts[i].setText("0");}}}

需要注意的是,我们无法再onCreate()方法中获得视图的宽高值,所以通过View的post()方法,再视图创建完毕后获得其宽高值。

接下来,只需要获得修改后的EditText的值,并将矩阵值设置给颜色矩阵即可。再Android程序中,使用一个一维数组来保存20个矩阵值,并通过ColorMatrix的set()方法,将一个一维数组转化为ColorMatrix,代码如下所示。

    //获取矩阵值private float[] getMatrix() {float[] colorMatrixs = new float[20];for (int i = 0; i < 20; i++) {colorMatrixs[i] = Float.valueOf(mEts[i].getText().toString());}return colorMatrixs;}//将矩阵值设置到图像private void setImageMatrix(float[] colorMatrixs) {Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);ColorMatrix matrix = new ColorMatrix();matrix.set(colorMatrixs);Canvas canvas = new Canvas(bmp);Paint paint = new Paint();paint.setColorFilter(new ColorMatrixColorFilter(matrix));canvas.drawBitmap(bitmap, 0, 0, paint);imageView.setImageBitmap(bmp);}

最后,设置好两个按钮的点击事件即可,一个是将现有矩阵作用到图像,另一个是将现有矩阵恢复到初始状态,再作用到图像,即还原图像,代码如下所示。

    public void btnChanged(View view){setImageMatrix(getMatrix());}public void btnReset(View view){initMatrix();setImageMatrix(getMatrix());}

程序的原图,设置偏移量和系数,来看看效果是否与预期相同。

         

3.常用图像颜色矩阵处理效果

研究图像色彩处理的人,正式研究如何通过某种算法,将对应的颜色矩阵值作用到原图像上,从而形成新的色彩风格的图像。下面我们就展现一些比较经典、常用的颜色处理效果对应的颜色矩阵,让读者朋友对颜色矩阵有一个更清晰的认识。

3.1灰度效果

颜色矩阵如下所示,处理效果图如下所示。

            0.33f,0.59f,0.11f,0,0,0.33f,0.59f,0.11f,0,0,0.33f,0.59f,0.11f,0,0,0,0,0,1,0

3.2图像反转

颜色矩阵如下所示,处理效果如下所示。

            -1,0,0,1,1,0,-1,0,1,1,0,0,-1,1,1,0,0,0,1,0

3.3怀旧效果

颜色矩阵如下所示,处理效果如下所示。

            0.393f,0.769f,0.189f,0,0,0.349f,0.686f,0.168f,0,0,0.272f,0.534f,0.131f,0,0,0,0,0,1,0

3.4去色效果

颜色效果如下所示,处理效果如下所示。

            1.5f,1.5f,1.5f,0,-1,1.5f,1.5f,1.5f,0,-1,1.5f,1.5f,1.5f,0,-1,0,0,0,1,0

3.5 高饱和度

颜色效果如下所示,处理效果如下所示。

            1.438f,-0.122f,-0.016f,0,-0.03f,-0.062f,1.378f,-0.016f,0,0.05f,-0.062f,-0.122f,1.483f,0,-0.02f,0,0,0,1,0

4. 像素点分析

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

在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, width, 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);
        在通过如下代码将新的ARGB值合成像素点。
newPx[i] = Color.argb(a,r1,g1,b1);
        最后通过如下所示代码,将处理之后的像素点数组重新set给我们的Bitmap,从而达到图像处理的目的。
bitmap.getPixels(newPx, 0, width, 0, 0, width, height);

5.常用图像像素点处理效果

        这些方法同样是专业认识的研究成功,通过这些特定的算法对每个像素点进行处理,就可以得到不同的处理效果。下面展示一些常用的图像处理算法,这些算法大家可能会发现与前面通过矩阵来处理图像的算法有些类似。

5.1底片效果

        若存在ABC3个像素点,要求B点对应的的底片效果算法,代码如下所示。显示效果如下所示。
B.r = 255 - B.r;
B.g = 255 - B.g;
B.b = 255 - B.b;


        实现代码如下所示。
    public static Bitmap handleImageNegative(Bitmap bm) {int width = bm.getWidth();int height = bm.getHeight();int color;int r,g,b,a;Bitmap bitmap = 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;i<width*height; i++) {color = oldPx[i];r = Color.red(color);g = Color.green(color);b = Color.blue(color);a = Color.alpha(color);r = 255-r;g = 255-g;b = 255-b;if(r > 255){r = 255;} else if (r < 0) {r = 0;}if(g > 255){g = 255;} else if (g < 0) {g = 0;}if(b > 255){b = 255;} else if (r < 0) {b = 0;}newPx[i] = Color.argb(a,r,g,b);}bitmap.setPixels(newPx,0,width,0,0,width,height);return bitmap;}
        由于后面的几种算法的代码与以上基本一直,只是修改了部分算法。因此,后面的代码就不具体贴出来了。

5.2老照片效果

        求某像素点的老照片效果算法,代码如下,效果图如下所示。
            r = (int)(0.393*r + 0.769*g + 0.189*b);g = (int)(0.349*r + 0.686*g + 0.168*b);b = (int)(0.272*r + 0.534*g + 0.131*b);

    public static Bitmap handleImageOld(Bitmap bm) {int width = bm.getWidth();int height = bm.getHeight();int color;int r,g,b,a;Bitmap bitmap = 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;i<width*height; i++) {color = oldPx[i];r = Color.red(color);g = Color.green(color);b = Color.blue(color);a = Color.alpha(color);r = (int)(0.393*r + 0.769*g + 0.189*b);g = (int)(0.349*r + 0.686*g + 0.168*b);b = (int)(0.272*r + 0.534*g + 0.131*b);if(r > 255){r = 255;} else if (r < 0) {r = 0;}if(g > 255){g = 255;} else if (g < 0) {g = 0;}if(b > 255){b = 255;} else if (r < 0) {b = 0;}newPx[i] = Color.argb(a,r,g,b);}bitmap.setPixels(newPx,0,width,0,0,width,height);return bitmap;}



5.3浮雕效果
若存在ABC3个像素点,要求B点对应的浮点效果算法,代码如下,显示效果如下。

B.r = C.r - B.r + 127;
B.g = C.g - B.g + 127;
B.b = C.b - B.b + 127;

    public static Bitmap handleImageRelief(Bitmap bm) {int width = bm.getWidth();int height = bm.getHeight();int color;int r,g,b,a;Bitmap bitmap = 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;i<width*height; i++) {color = oldPx[i];r = Color.red(color);g = Color.green(color);b = Color.blue(color);a = Color.alpha(color);if(i != width*height-1){int r1,g1,b1;color = oldPx[i+1];r1 = Color.red(color);g1 = Color.green(color);b1 = Color.blue(color);r = r1 - r + 127;g = g1 - g + 127;b = b1 - b + 127;}if(r > 255){r = 255;} else if (r < 0) {r = 0;}if(g > 255){g = 255;} else if (g < 0) {g = 0;}if(b > 255){b = 255;} else if (r < 0) {b = 0;}newPx[i] = Color.argb(a, r, g, b);}bitmap.setPixels(newPx,0,width,0,0,width,height);return bitmap;}


												

Android图像处理之色彩特效处理相关推荐

  1. android 特效绘图,Android绘图机制与处理技巧——Android图像处理之图形特效处理...

    Android变形矩阵--Matrix 对于图像的图形变换,Android系统是通过矩阵来进行处理的,每个像素点都表达了其坐标的X.Y信息.Android的图形变换矩阵是一个3x3的矩阵,如下图所示: ...

  2. Android图像处理之图形特效处理

    前面我们了解了关于图像色彩处理的相关技巧,下面继续来探讨图形图像方面的处理技巧. 1.Android变形矩阵------Matrix 对于图像的色彩处理,Android系统提供了ColorMatrix ...

  3. Android图像处理之画笔特效处理

    不管是在我们的世界里,还是在Android的世界里,想要向神笔马良一样画出各种精彩绝伦的画,就必须得有一个前提------要有一支神奇的画笔.在前面的学习中,我们已经初步了解了一些常用的画笔属性,比如 ...

  4. Android图像处理整理

    Android图像处理整理 参考:http://blog.csdn.net/luzhenyuxfcy/article/details/49427781 我们常用的处理方式基本都是在对像素矩阵按照一定的 ...

  5. android图像处理系列之五-- 给图片添加边框(中)

    前面一篇讲到给图片加边框的方式,只能给图片加一些有规则的边框,如果想加一些比较精美的效果,就有点麻烦了.下面就给出解决这个问题的思路. 思路是:一些比较精美的花边图片我们是很难用代码控制,就目前本人水 ...

  6. android 涂鸦之图片叠加,android图像处理系列之七--图片涂鸦,水印-图片叠加...

    图片涂鸦和水印其实是一个功能,实现的方式是一样的,就是一张大图片和一张小点图片叠加即可.前面在android图像处理系列之六--给图片添加边框(下)-图片叠加中也讲到了图片叠加,里面实现的原理是直接操 ...

  7. Android系统联系人全特效实现(下),字母表快速滚动

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9050671 在上一篇文章中,我和大家一起实现了类似于Android系统联系人的分组 ...

  8. Android系统联系人全特效实现(上),分组导航和挤压动画

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9033553 记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根 ...

  9. android 滑动缩放监听,基于Android的ViewPager动画特效实现页面左右滑动效果(实现缩放...

    基于Android的ViewPager动画特效实现页面左右滑动效果(实现缩放 基于Android的ViewPager动画特效实现页面左右滑动效果(实现缩放和透明效果) 在上一个项目的基础上做修改,项目 ...

最新文章

  1. 西湖大学鞠峰组:环境宏病毒组学分析思路与常用工具
  2. 汇编: dosbox命令
  3. 通讯系统经验谈【一】TCP连接状态分析:SYNC_RECV,CLOSE_WAIT,TIME_WAIT
  4. Check failed: error == cudaSuccess (74 vs. 0) misaligned address的解决方法
  5. 1. 赋值运算符函数
  6. 5 年之后,产品经理,没了?
  7. 拓端tecdat|【视频】R语言生存分析原理与晚期肺癌患者分析案例|数据分享
  8. 红米note5系统Android11,红米Note5-MIUI11 开发版|超多功能|Xposed|ROOT|桌面布局-刷机之家...
  9. 深度学习之语义分割(SegNet)
  10. 什么是APS高级计划排程系统?APS计划排产有什么功能和作用?
  11. 配置Pod的liveness和readiness探针
  12. axios请求下载excel文件以及文件乱码问题
  13. 中国古代称谓专有名词
  14. Docker 拷贝文件到容器里面
  15. vue实现不同页面显示不同标题
  16. 我的世界1.8.9作弊java_我的世界超强作弊代码大全 掌控整个世界
  17. GB2312编码一级汉字表
  18. 4g/GPRS DTU 开发板软件代码硬件图纸料
  19. selenium网页自动登录、打卡(一)
  20. 世界首富身价1.93万亿,相当于8个马云,5个钟睒睒

热门文章

  1. java fileinputstream_java – 需要将AssetInputStream转换为FileInputStream
  2. 写给那些正在找工作的朋友
  3. php 时间格式 毫秒,php获取当前时间的毫秒数详解
  4. 缓存一致性协议和CPU缓存架构(MESI协议)、伪共享
  5. 解决“您可以尝试添加 --skip-broken 选项来解决改问题“错误
  6. 修改 下载仓库为淘宝镜像 npm config set registry https://registry.npmjs.org/, 如果要发布自己的镜像需要修改回来 npm
  7. 用Pdg2.DLL解码PDG的境界
  8. 【调剂】985华东师范大学数据科学与工程学院校企联合非全日制专硕调剂
  9. 五行Python实现验证码识别,太稳了
  10. 编出个区块链:实现区块链的椭圆曲线签名和认证