美文网首页
Android像素二维数组转图像的实现

Android像素二维数组转图像的实现

作者: 我说的这句话是谎话 | 来源:发表于2020-03-30 09:38 被阅读0次

    Android上需要生成图片首先想到的是 createBitmap API,看了一下之后,实现了第一种方法

    纯Java实现

        private Bitmap createBitmap(int[][] dataArray) {
            // 转一维数组
            byte[] newArray = new byte[dataArray.length * dataArray[0].length];
    
            int index = 0;
            for (int row = 0; row < dataArray.length; row++) {
                for (int column = 0; column < dataArray[0].length; column++) {
                    newArray[index++] = (byte)dataArray[row][column];
                }
            }
        
            // 注意 width,height 与 二维数组 row,colume 的对应关系
            Bitmap bitmap = Bitmap.createBitmap(dataArray[0].length, dataArray.length, Bitmap.Config.ARGB_8888);
    
            int pixels[] = new int[dataArray[0].length * dataArray.length];
            for (int i = 0; i < pixels.length; ++i) {
                //关键代码,生产灰度图
                pixels[i] = newArray[i] * 256 * 256 + newArray[i] * 256 + newArray[i] + 0xFF000000;
            }
        
            // 设置像素值
            bitmap.setPixels(pixels, 0, 128, 0, 0, 128, 19500);
    
            if (bitmap != null) {
                // 只是做图片缩放
                bitmap = zoomBitmap(bitmap, 440, 590);
            }
    
            return bitmap;
    
        }
    
        /**
         * 图片缩放
         * @param
         * @param bitmap 对象
         * @param w 要缩放的宽度
         * @param h 要缩放的高度
         * @return newBmp 新 Bitmap对象
         */
         public static Bitmap zoomBitmap (Bitmap bitmap,int w, int h){
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            Matrix matrix = new Matrix();
            float scaleWidth = ((float) w / width);
            float scaleHeight = ((float) h / height);
            matrix.postScale(scaleWidth, scaleHeight);
            Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
                    matrix, true);
            return newBmp;
         }
    

    这里的二维数组是直接拿来用的,像素数组我是拿到的一个 csv文件解析出来的,这里就不赘述了,用的是 jxl 库。

    完成之后发现实在是太慢了,出去解析 csv 的时间,光生成图片的时间都是以 秒 来计算的。

    爆火副业赚钱全攻略

    然后就换成了 OpenCV 来实现。结合 在现有AS项目中新增OpenCV c++库的支持,现在缺少的就只有 实现 转换图片的函数就可以了。

    OpenCV Jni实现

        public static native Bitmap array2Bitmap(int width, int height, int[][] original_data, Bitmap bitmap);
    

    现在的 AS 都已经支持可以根据提示 自动在 cpp 文件生成对应的函数了

    extern "C"
    JNIEXPORT jobject JNICALL
    Java_xyz_jimbray_healthydemo_JNITools_array2Bitmap(JNIEnv *env, jclass type, jint width, jint height,
                                                                  jobjectArray original_data, jobject bitmap) {
    
        jint rows = env->GetArrayLength(original_data);
        jarray array = (jintArray)(env->GetObjectArrayElement(original_data, 0));
    
        jint cols = env->GetArrayLength(array);
    
        // 转换二维数组
        vector<vector<int>> swp(rows, vector<int>(cols));
    
        for (jint i = 0; i < rows; i++) {
            array = (jintArray)(env->GetObjectArrayElement(original_data, i));
    
            // 获取指针
            jint *col_data = env->GetIntArrayElements((jintArray)array, 0);
    
            for (jint j = 0; j < cols; j++) {
                swp[i][j] = col_data[j];
            }
    
            // 释放指针
            env->ReleaseIntArrayElements((jintArray)array, col_data, 0);
        }
    
        // 注意 width,height 的参数位置
        cv::Mat mat = cv::Mat(height, width, CV_8U);
    
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                mat.at<uchar>(i, j) = swp[i][j];
            }
        }
    
        // 缩放图片以方便展示
        cv::resize(mat, mat, cv::Size(440, 590), 0, 0, CV_INTER_LINEAR);
    
        //get source bitmap's config
        jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
        jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
        jobject bitmap_config = env->CallObjectMethod(bitmap, mid);
        jobject _bitmap = mat_to_bitmap(env, mat, false, bitmap_config);
    
        AndroidBitmap_unlockPixels(env, bitmap);
    
        return _bitmap;
    
    }
    
    // 不要忘记定义哦
    jobject mat_to_bitmap(JNIEnv * env, cv::Mat& src, bool needPremultiplyAlpha, jobject bitmap_config){
    
        jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
        jmethodID mid = env->GetStaticMethodID(java_bitmap_class,
                                               "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    
        jobject bitmap = env->CallStaticObjectMethod(java_bitmap_class,
                                                     mid, src.size().width, src.size().height, bitmap_config);
        AndroidBitmapInfo  info;
        void* pixels = 0;
    
        try {
            //validate
            CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
            CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4);
            CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
            CV_Assert(pixels);
    
            //type mat
            if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
                cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
                if(src.type() == CV_8UC1){
                    cvtColor(src, tmp, CV_GRAY2RGBA);
                } else if(src.type() == CV_8UC3){
                    cvtColor(src, tmp, CV_RGB2RGBA);
                } else if(src.type() == CV_8UC4){
                    if(needPremultiplyAlpha){
                        cvtColor(src, tmp, COLOR_RGBA2mRGBA);
                    }else{
                        src.copyTo(tmp);
                    }
                }
    
            } else{
                cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
                if(src.type() == CV_8UC1){
                    cvtColor(src, tmp, CV_GRAY2BGR565);
                } else if(src.type() == CV_8UC3){
                    cvtColor(src, tmp, CV_RGB2BGR565);
                } else if(src.type() == CV_8UC4){
                    cvtColor(src, tmp, CV_RGBA2BGR565);
                }
            }
            AndroidBitmap_unlockPixels(env, bitmap);
            return bitmap;
        } catch(cv::Exception e){
            AndroidBitmap_unlockPixels(env, bitmap);
            jclass je = env->FindClass("org/opencv/core/CvException");
            if(!je) je = env->FindClass("java/lang/Exception");
            env->ThrowNew(je, e.what());
            return bitmap;
        } catch (...){
            AndroidBitmap_unlockPixels(env, bitmap);
            jclass je = env->FindClass("java/lang/Exception");
            env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
            return bitmap;
        }
    }
    

    在 Java 层调用

     private Bitmap createBitmap(int[][] dataArray) {
       Bitmap src = Bitmap.createBitmap(dataArray[0].length, dataArray.length, Bitmap.Config.ARGB_8888);
               Bitmap bitmap = JNITools.array2Bitmap(dataArray[0].length, dataArray.length, dataArray, src);
       return bitmap;
    }
    

    完成。

    相对前面的 纯Java版本,速度现在是以 毫秒 计,根本没有对比的资格。

    已发布至 Jimbray-我说的这句话是谎话

    相关文章

      网友评论

          本文标题:Android像素二维数组转图像的实现

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