图形图像处理 - Android 滤镜效果

作者: 你也不知道 | 来源:发表于2020-07-16 16:50 被阅读0次

    年初来深圳正式开始从事音视频开发,为啥我想从事音视频开发呢?有一个简单的理由是我想建立起自己的技术壁垒,别人不能做的你能做,别人解决不了的你能解决。我们工作多年甚至于做了几十个项目,如果我们不能从项目中去学习新的东西,那技术就只能停滞不前了。当然有哥们建议我说,你学的东西太多了但是不精,因此同样我也建议大家还是先把 Java 基础和 Android 基础打牢。后面我将写下一些图形图像处理的文章,很多是我自己学来的,也有些是我工作中遇到的。感兴趣的哥们可以看下,也希望可以帮大家少走一些弯路。文章和视频主要还是以 NDK 为主,因此希望各位看官能有一些 c 和 c++ 的基础,有一些数据结构和算法的基础,如果没有建议大家去看看我之前写的一些文章。

    1. OpenCV 安装

    OpenCV 是一个计算视觉的开源库,主要算法涉及图像处理和机器学习。是 Intel 公司贡献出来的,因为它可以免费应用在商业和研究领域,且国内大多数图像处理相关的应用程序中都采用的是 OpenCV,因此后面很大一部分内容我们都基于 OpenCV 来讲。官方给我们封装了很多 java 层的接口,但总的来说可扩展性不是很高,因此后面我们主要采用 c++ 来写,然后自己编译成 so 库来供 Android 调用。为了便于方法和算法的讲解,我们暂时基于 VS 环境来编写代码,大家如果用的是 mac 电脑,可以去看看我之前的《NDK开发前奏 - 实现支付宝人脸识别功能》 ,也可以直接基于 android 环境开发。接下来我们一步步来搭建 VS 的开发环境:

    首先我们找到 opencv 的官网 https://opencv.org/opencv-4-0-0-rc.html ,目前最高版本是 4.0 点击 Win pack 进行下载。下载下来是一个 exe 文件,我们不要安装直接解压就好。找到 build\x64\vc14\bin 下,把目录进行拷贝配置环境变量:

    环境变量配置

    然后新建 VS 空项目,找到菜单栏的 调试窗口 -> 属性 -> 配置属性 -> VC++ 目录


    在包含目录和库目录中新增我们 opencv 的解压目录。然后我们写一个简单实例测试能即可:
    #include <opencv2/opencv.hpp>
    #include <iostream>
    
    using namespace cv;
    
    void main(){
        // 本地读取一张图片
        Mat src = imread("C:/Users/hcDarren/Desktop/android/NDK/NDK_Day56/test1.jpg");
        Mat gray;
        // 转灰度
        cvtColor(src, gray, COLOR_BGR2GRAY);
        // 将灰度图显示到窗口
        namedWindow("test pic",CV_WINDOW_NORMAL);
        imshow("test pic", gray);
        waitKey(0);
    }
    

    大家按照我这个配置去做,可能还是会遇到很多问题。但所有的问题都离不开两个方面,一个是头文件,一个是实现的 dll 动态库。

    2. Android 滤镜效果

    我们来看一个比较常见同时也是非常简单的例子,打开 QQ 空间发说说图片时会有一个滤镜功能,我们可以自己先去看看那些滤镜效果。

    实现这样的效果有多种方案,Java 层用 ColorMatrix 矩阵来实现,Java 层操作 Bitmap 像素,Native 层操作 Bitmap 像素指针等等。这里我把三种方案都写上,希望大家能够做到举一反三。以彩色图转灰度图为例:

    2.1 Java 层用 ColorMatrix 矩阵来实现

        public static Bitmap gary(Bitmap bitmap) {
            Bitmap gary = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
            Canvas canvas = new Canvas(gary);
            Paint paint = new Paint();
            // 比较流行的方法。几个加权系数0.3,0.59,0.11是根据人的亮度感知系统调节出来的参数,是个广泛使用的标准化参数
            ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                    0.30f, 0.59f, 0.11f, 0, 0,
                    0.30f, 0.59f, 0.11f, 0, 0,
                    0.30f, 0.59f, 0.11f, 0, 0,
                    0, 0, 0, 1f, 0
            });
            ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
            paint.setColorFilter(colorFilter);
            canvas.drawBitmap(bitmap, 0, 0, paint);
            return gary;
        }
    

    2.2 Java 层操作 Bitmap 像素

        public static Bitmap gary(Bitmap bitmap) {
    
            int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
            bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    
            for (int i = 0; i < pixels.length; i++) {
                int pixel = pixels[i];
                int a = (pixel >> 24) & 0xff;
                int r = (pixel >> 16) & 0xff;
                int g = (pixel >> 8) & 0xff;
                int b = pixel & 0xff;
    
                int gery = (int) (0.30f * r + 0.59f * g + 0.11f * b);
                pixels[i] = (a << 24) |  (gery << 16) |  (gery << 8)  |  gery;
            }
    
            Bitmap gary = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
            gary.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    
            return gary;
        }
    

    2.3 Native 层操作 Bitmap 像素指针

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_ndk_day51_BitmapUtil_gary(JNIEnv *env, jclass type, jobject bitmap) {
        // 获取 Bitmap 信息
        AndroidBitmapInfo bitmapInfo;
        AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
    
        // 锁定画布
        void *pixels;
        AndroidBitmap_lockPixels(env, bitmap, &pixels);
    
        for (int i = 0; i < bitmapInfo.width * bitmapInfo.height; ++i) {
            uint32_t *p_pixel = reinterpret_cast<uint32_t *>(pixels) + i;
            uint32_t pixel = *p_pixel;
            int a = (pixel >> 24) & 0xff;
            int r = (pixel >> 16) & 0xff;
            int g = (pixel >> 8) & 0xff;
            int b = pixel & 0xff;
            int gery = r * 0.3f + g * 0.59f + b * 0.11f;
            *p_pixel = (a << 24) | (gery << 16) | (gery << 8) | gery;
        }
        
        // 解锁画布
        AndroidBitmap_unlockPixels(env, bitmap);
    }
    

    如果我们不是很了解矩阵的操作,可以去 Google 查查资料。上面的代码也还会有些许问题,如果我们想用到项目中还得好好思考思考。

    视频地址:https://pan.baidu.com/s/1FqGwalxQimTwfoMKvIZNXw
    视频密码:5xnx

    相关文章

      网友评论

        本文标题:图形图像处理 - Android 滤镜效果

        本文链接:https://www.haomeiwen.com/subject/uzxmhktx.html