Android开发——Bitmap图像效果

一、Bitmap(位图)

在Android开发中,一般对图像的处理就是Bitmap(位图),它包含了图像的全部数据,即点阵和颜色值,点阵就是包含像素点的矩阵,而颜色值就是ARGB,分别代表透明、红色、绿色、蓝色通道,它们共同决定了像素点的颜色。

  1. 位图(Bitmap): 位图(Bitmap)是一种数字图像表示,它由像素矩阵组成,每个像素点都包含颜色信息。在计算机图形学中,位图通常指的是一种图像文件格式,如BMP、PNG、JPEG等,它们包含了图像的完整数据。

  2. 像素点(Pixel): 像素是构成数字图像的最小单元。在位图中,每个像素点都有一个特定的位置(x, y坐标)和颜色值。像素点的集合构成了图像的完整画面。

  3. 点阵(Pixel Array): 点阵是组成位图的像素点的集合。在二维空间中,这些像素点排列成一个矩形网格,每个像素点都有一个唯一的坐标位置。

  4. 颜色值(ARGB): 在Android中,颜色值通常以ARGB(Alpha, Red, Green, Blue)的形式表示。每个颜色通道都有8位(即256级),所以ARGB颜色值可以表示为一个32位的整数。Alpha通道控制像素的透明度,取值范围从0(完全透明)到255(完全不透明)。红色、绿色和蓝色通道则控制颜色的强度,它们的组合可以产生几乎所有可见的颜色。

  5. Bitmap.ConfigBitmap.Config是一个枚举类型,用于指定Bitmap的配置。它定义了Bitmap的像素数据的存储格式。常见的配置有ARGB_8888(每个像素包含32位,即8位Alpha, 8位Red, 8位Green, 8位Blue),RGB_565(每个像素包含16位,即5位Red, 6位Green, 5位Blue,没有Alpha通道),以及ARGB_4444(每个像素包含16位,即4位Alpha, 4位Red, 4位Green, 4位Blue)等。

二、颜色矩阵

上面已经讲到,像素点是构成图像的最小单元。每个像素点除了包含位置坐标外,还包含一定的颜色信息,这个颜色信息是用一个颜色矩阵分量来保存的,即下图的RGBA1(矩阵C).
在这里插入图片描述

而在Android系统中,颜色矩阵是用一个4*5的数字矩阵来表示的(矩阵A,由一维数组构成)。

在这里插入图片描述

它们的乘积(矩阵R)即为屏幕上显示的图像颜色,这里的RGBA取值应在0~255之间。

在这里插入图片描述

R=(R1, G1, B1, A1)

特别的,当A为如下矩阵时,根据上面的矩阵相乘的公式,R=C,原来像素点的颜色矩阵没有改变,因此称该矩阵为单位矩阵。一般初始化图像的时候,我们会构建它。

在这里插入图片描述

单位矩阵

我们上面说了矩阵R是矩阵A和矩阵C的乘积,即为屏幕上所显示的图像颜色。矩阵C是我们原来Bitmap图片的颜色,因此当我们想改变屏幕上所显示的图像颜色(矩阵R)时,我们可以通过改变矩阵C,来实现各种变换效果。

关于矩阵R,谷歌中帮我们将它的属性和方法封装成类ColorMatrix,其中有许多简单的操作方法。其中最核心的代码如下:

 //构建出ColorMatrix对象
  ColorMatrix colorMatrix = new ColorMatrix();
  //通过set方法把对应的4 * 5数字矩阵(一维数组)传入
  colorMatrix.set(float[] src);
  //构建出颜色过滤器ColorMatrixColorFilter,再通过ImageView设置
  mImageView.setColorFilter(new ColorMatrixColorFilter(colorMatrix));

其实重点就在于这个4 * 5数组矩阵的数值的搭配。除了以上简单粗暴的set对应的颜色矩阵,ColorMatrix类中还提供了许多方法,比如可以调整图像的色相、饱和度、灰度等。下面整理了一些具体的实现。

三、实现案例

(基于EasyPhotos)

在这里插入图片描述

(一)Activity中调用逻辑

 case R.id.photo_greymasks:
                //这里检查selectedPhotoList列表是否为空。如果用户没有选择任何照片,那么接下来的操作将不会执行。
                if (selectedPhotoList.isEmpty()) {
                    Toast.makeText(this, "没选图片", Toast.LENGTH_SHORT).show();
                    return true;
                }
                //BitmapFactory.decodeFile方法用于将文件路径转换为Bitmap。
                Bitmap originalBitmap = BitmapFactory.decodeFile(selectedPhotoList.get(0).getAvailablePath());
                //创建了原始Bitmap的一个副本,确保在应用滤镜时不会修改原始图片。
                originalBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);

                // 应用灰度滤镜
                if(originalBitmap!=null){
                    Bitmap filteredBitmap = getHuiDu(originalBitmap);
                    // 将应用了滤镜的Bitmap设置到bitmapView上,这样用户就可以看到处理后的效果。
                    bitmapView.setVisibility(View.VISIBLE);
                    bitmapView.setImageBitmap(filteredBitmap);

                    // 在不再需要原始图片时回收它
                    BitmapUtils.recycle(originalBitmap);
                    //弹出一个短暂的提示框,告诉用户图片已经成功应用了灰度滤镜。
                    Toast.makeText(SampleActivity.this, "图片已应用灰度滤镜", Toast.LENGTH_SHORT).show();

                }
                //关闭侧边栏
                drawer.closeDrawer(GravityCompat.START);
                break;

其他几种Bitmap处理效果的调用逻辑同上。

(二)Bitmap类型图片几种滤镜/特效实现函数及效果图

1.获取灰度图片

//获取灰度图片
    public static Bitmap getHuiDu(Bitmap bitMap) {

        int width, height;
        height = bitMap.getHeight();
        width = bitMap.getWidth();
        Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        //创建一个新的Canvas对象c,它将用于在新的Bitmap上绘制图像。
        Canvas c = new Canvas(bmpGrayscale);
        Paint paint = new Paint();
        //创建一个新的ColorMatrix对象cm,用于定义颜色变换矩阵。
        ColorMatrix cm = new ColorMatrix();
        //设置颜色矩阵的饱和度为0,将所有颜色都将被转换为灰度。
        cm.setSaturation(0);
        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
        paint.setColorFilter(f);
        //使用Canvas对象c在新的Bitmap``bmpGrayscale上绘制原始Bitmap``bitMap,位置为(0, 0),使用带有颜色过滤的Paint对象paint。
        c.drawBitmap(bitMap, 0, 0, paint);
        return bmpGrayscale;
    }

效果图

在这里插入图片描述

2.获取黑白图片

public static Bitmap convertToBMW(Bitmap bmp) {
        int width = bmp.getWidth(); // 获取位图的宽
        int height = bmp.getHeight(); // 获取位图的高
        int[] pixels = new int[width * height]; // 通过位图的大小创建像素点数组
        // 设定二值化的域值,默认值为100
        int tmp = 150;
        bmp.getPixels(pixels, 0, width, 0, 0, width, height);
        int alpha = 0xFF << 24;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int grey = pixels[width * i + j];
                // 分离三原色
                alpha = ((grey & 0xFF000000) >> 24);
                int red = ((grey & 0x00FF0000) >> 16);
                int green = ((grey & 0x0000FF00) >> 8);
                int blue = (grey & 0x000000FF);
                int i1 = 0xFFFF;


                if (red > tmp) {
                    red = 255;
                } else {
                    red = 0;
                }
                if (blue > tmp) {
                    blue = 255;
                } else {
                    blue = 0;
                }
                if (green > tmp) {
                    green = 255;
                } else {
                    green = 0;
                }
                pixels[width * i + j] = alpha << 24 | red << 16 | green << 8
                        | blue;
                if (pixels[width * i + j] == -1) {
                    pixels[width * i + j] = -1;

                } else {
                    pixels[width * i + j] = -16777216;
                }
            }
        }
        // 新建图片
        Bitmap newBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        // 设置图片数据
        newBmp.setPixels(pixels, 0, width, 0, 0, width, height);
        Bitmap resizeBmp = ThumbnailUtils.extractThumbnail(newBmp, width, height);

//        return getHuiDu(resizeBmp, AppApplication.getIntance());
        return resizeBmp;
    }

效果图

在这里插入图片描述

3.生成底片效果

/**
     * 通过更改图片像素点的RGBA值,生成底片效果
     * @param scrBitmap
     * @return 
     */
    public static Bitmap beautyImage(Bitmap scrBitmap) {
        int width = scrBitmap.getWidth();
        int height = scrBitmap.getHeight();
        int count = width * height;
        int[] oldPixels = new int[count];
        int[] newPixels = new int[count];
        scrBitmap.getPixels(oldPixels, 0, width, 0, 0, width, height);
        for (int i = 0; i < oldPixels.length; i++) {
            int pixel = oldPixels[i];
            int r = Color.red(pixel);
            int g = Color.green(pixel);
            int b = Color.blue(pixel);
            r = 255 - r;
            g = 255 - g;
            b = 255 - b;
            if (r > 255) {
                r = 255;
            }
            if (g > 255) {
                g = 255;
            }
            if (b > 255) {
                b = 255;
            }
            if (r < 0) {
                r = 0;
            }
            if (g < 0) {
                g = 0;
            }
            if (b < 0) {
                b = 0;
            }
            newPixels[i] = Color.rgb(r, g, b);
        }
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(newPixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

效果图

在这里插入图片描述

4.怀旧风格图片效果

/**
     * 生成怀旧风格
     * @param bmp
     * @return
     */
    private Bitmap oldRemeber(Bitmap bmp)
    {
        // 速度测试
        long start = System.currentTimeMillis();
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        int pixColor = 0;
        int pixR = 0;
        int pixG = 0;
        int pixB = 0;
        int newR = 0;
        int newG = 0;
        int newB = 0;
        int[] pixels = new int[width * height];
        bmp.getPixels(pixels, 0, width, 0, 0, width, height);
        for (int i = 0; i < height; i++)
        {
            for (int k = 0; k < width; k++)
            {
                pixColor = pixels[width * i + k];
                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, newR > 255 ? 255 : newR, newG > 255 ? 255 : newG, newB > 255 ? 255 : newB);
                pixels[width * i + k] = newColor;
            }
        }

        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        long end = System.currentTimeMillis();
        return bitmap;
    }

效果图

在这里插入图片描述

5.图片模糊效果

// 图片模糊效果
    public static Bitmap convertBlur(Bitmap origin) {
        int width = origin.getWidth();
        int height = origin.getHeight();
        int hRadius = width > 150 ? width / 150 : 1; // 水平方向模糊度
        int vRadius = height > 150 ? height / 150 : 1; // 垂直方向模糊度
        int iterations = 7; // 模糊迭代度
        int[] inPixels = new int[width * height];
        int[] outPixels = new int[width * height];
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        origin.getPixels(inPixels, 0, width, 0, 0, width, height);
        for (int i = 0; i < iterations; i++) {
            blur(inPixels, outPixels, width, height, hRadius);
            blur(outPixels, inPixels, height, width, vRadius);
        }
        blurFractional(inPixels, outPixels, width, height, hRadius);
        blurFractional(outPixels, inPixels, height, width, vRadius);
        bitmap.setPixels(inPixels, 0, width, 0, 0, width, height);
        return bitmap;
    }
    private static void blur(int[] in, int[] out, int width, int height, int radius) {
        int widthMinus1 = width - 1;
        int tableSize = 2 * radius + 1;
        int[] divide = new int[256 * tableSize];
        for (int i = 0; i < 256 * tableSize; i++) {
            divide[i] = i / tableSize;
        }
        int inIndex = 0;
        for (int y = 0; y < height; y++) {
            int outIndex = y;
            int ta = 0, tr = 0, tg = 0, tb = 0;
            for (int i = -radius; i <= radius; i++) {
                int rgb = in[inIndex + clamp(i, 0, width - 1)];
                ta += (rgb >> 24) & 0x99; // 调整灰度。0x99表示半透明
                tr += (rgb >> 16) & 0xff; // 调整红色
                tg += (rgb >> 8) & 0xff; // 调整绿色
                tb += rgb & 0xff; // 调整蓝色
            }

            for (int x = 0; x < width; x++) {
                out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8) | divide[tb];
                int i1 = x + radius + 1;
                if (i1 > widthMinus1) {
                    i1 = widthMinus1;
                }
                int i2 = x - radius;
                if (i2 < 0) {
                    i2 = 0;
                }
                int rgb1 = in[inIndex + i1];
                int rgb2 = in[inIndex + i2];
                ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
                tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
                tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
                tb += (rgb1 & 0xff) - (rgb2 & 0xff);
                outIndex += height;
            }
            inIndex += width;
        }
    }

    public static void blurFractional(int[] in, int[] out, int width, int height, float radius) {
        radius -= (int) radius;
        float f = 1.0f / (1 + 2 * radius);
        int inIndex = 0;
        for (int y = 0; y < height; y++) {
            int outIndex = y;
            out[outIndex] = in[0];
            outIndex += height;
            for (int x = 1; x < width - 1; x++) {
                int i = inIndex + x;
                int rgb1 = in[i - 1];
                int rgb2 = in[i];
                int rgb3 = in[i + 1];
                int a1 = (rgb1 >> 24) & 0xff;
                int r1 = (rgb1 >> 16) & 0xff;
                int g1 = (rgb1 >> 8) & 0xff;
                int b1 = rgb1 & 0xff;
                int a2 = (rgb2 >> 24) & 0xff;
                int r2 = (rgb2 >> 16) & 0xff;
                int g2 = (rgb2 >> 8) & 0xff;
                int b2 = rgb2 & 0xff;
                int a3 = (rgb3 >> 24) & 0xff;
                int r3 = (rgb3 >> 16) & 0xff;
                int g3 = (rgb3 >> 8) & 0xff;
                int b3 = rgb3 & 0xff;
                a1 = a2 + (int) ((a1 + a3) * radius);
                r1 = r2 + (int) ((r1 + r3) * radius);
                g1 = g2 + (int) ((g1 + g3) * radius);
                b1 = b2 + (int) ((b1 + b3) * radius);
                a1 *= f;
                r1 *= f;
                g1 *= f;
                b1 *= f;
                out[outIndex] = (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
                outIndex += height;
            }
            out[outIndex] = in[width - 1];
            inIndex += width;
        }
    }

效果图

在这里插入图片描述

6.LOMO特效

public static Bitmap lomoFilter(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int dst[] = new int[width * height];
        bitmap.getPixels(dst, 0, width, 0, 0, width, height);

        int ratio = width > height ? height * 32768 / width : width * 32768 / height;
        int cx = width >> 1;
        int cy = height >> 1;
        int max = cx * cx + cy * cy;
        int min = (int) (max * (1 - 0.8f));
        int diff = max - min;

        int ri, gi, bi;
        int dx, dy, distSq, v;

        int R, G, B;

        int value;
        int pos, pixColor;
        int newR, newG, newB;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                pos = y * width + x;
                pixColor = dst[pos];
                R = Color.red(pixColor);
                G = Color.green(pixColor);
                B = Color.blue(pixColor);

                value = R < 128 ? R : 256 - R;
                newR = (value * value * value) / 64 / 256;
                newR = (R < 128 ? newR : 255 - newR);

                value = G < 128 ? G : 256 - G;
                newG = (value * value) / 128;
                newG = (G < 128 ? newG : 255 - newG);

                newB = B / 2 + 0x25;

                // ==========边缘黑暗==============//
                dx = cx - x;
                dy = cy - y;
                if (width > height)
                    dx = (dx * ratio) >> 15;
                else
                    dy = (dy * ratio) >> 15;

                distSq = dx * dx + dy * dy;
                if (distSq > min) {
                    v = ((max - distSq) << 8) / diff;
                    v *= v;

                    ri = newR * v >> 16;
                    gi = newG * v >> 16;
                    bi = newB * v >> 16;

                    newR = ri > 255 ? 255 : (ri < 0 ? 0 : ri);
                    newG = gi > 255 ? 255 : (gi < 0 ? 0 : gi);
                    newB = bi > 255 ? 255 : (bi < 0 ? 0 : bi);
                }
                // ==========边缘黑暗end==============//

                dst[pos] = Color.rgb(newR, newG, newB);
            }
        }

        Bitmap acrossFlushBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        acrossFlushBitmap.setPixels(dst, 0, width, 0, 0, width, height);
        return acrossFlushBitmap;
    }

效果图

在这里插入图片描述

7.图片倒影特效

//设置倒影
    public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap){
        final int reflectionGap = 4;
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);

        Bitmap reflectionImage = Bitmap.createBitmap(bitmap,
                0, height/2, width, height/2, matrix, false);

        Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height/2), Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmapWithReflection);
        canvas.drawBitmap(bitmap, 0, 0, null);
        Paint deafalutPaint = new Paint();
        canvas.drawRect(0, height,width,height + reflectionGap,
                deafalutPaint);

        canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
        Paint paint = new Paint();
        LinearGradient shader = new LinearGradient(0,
                bitmap.getHeight(), 0, bitmapWithReflection.getHeight()
                + reflectionGap, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
        canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
                + reflectionGap, paint);

        return bitmapWithReflection;
    }

效果图

在这里插入图片描述

参考:

【1】Android开发之图像处理那点事——滤镜

【2】android实现滤镜 android滤镜开发https://blog.51cto.com/u_93011/6591870

【3】Android之多种Bitmap效果(4)https://www.cnblogs.com/wangxiuheng/p/4500579.html

【4】Android-Bitmap特效https://blog.csdn.net/ygc973797893/article/details/7207134

  • 29
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值