安卓Android Studio JNI开发问题澄清与汇总

这篇具有很好参考价值的文章主要介绍了安卓Android Studio JNI开发问题澄清与汇总。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Bitmap的操作

如何在JNI中读取和输出Bitmap

AndroidBitmap_lockPixels和AndroidBitmap_unlockPixels的底层逻辑就是在处理bitmap中的数据的时候,把内存锁定,防止像素缓存被改变导致数据变化。

这篇文章有具体介绍相关的机制

下面是Bitmap操作的示例代码:

#include <jni.h>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>

using namespace cv;

extern "C" {

JNIEXPORT jobject JNICALL Java_com_example_NativeUtils_processImage(JNIEnv *env, jobject obj, jobject bitmap) {
    AndroidBitmapInfo info;
    void *pixels = 0;

    //获取bitmap的信息
    if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
        return NULL;
    }

    //获取bitmap的像素数据
    if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
        return NULL;
    }

    //将像素数据转为Mat矩阵
    Mat src(info.height, info.width, CV_8UC4, pixels);

    //图像处理,这里以灰度化为例
    cvtColor(src, src, COLOR_RGBA2GRAY);

    //将处理后的图像数据转为Bitmap
    jobject newBitmap = createBitmap(env, src);

    //释放像素数据
    AndroidBitmap_unlockPixels(env, bitmap);

    return newBitmap;
}

jobject createBitmap(JNIEnv *env, Mat &src) {
    jclass bitmapCls = env->FindClass("android/graphics/Bitmap");
    jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapCls, "createBitmap", "(IIZ)Landroid/graphics/Bitmap;");
    jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapMethodID, src.cols, src.rows, Bitmap_Config::ARGB_8888);

    AndroidBitmapInfo info;
    void *pixels = 0;

    //获取Bitmap的像素数据
    if (AndroidBitmap_getInfo(env, newBitmap, &info) < 0) {
        return NULL;
    }
    if (AndroidBitmap_lockPixels(env, newBitmap, &pixels) < 0) {
        return NULL;
    }

    //将Mat矩阵中的数据复制到Bitmap中
    uint8_t *srcPixels = src.data;
    uint8_t *dstPixels = reinterpret_cast<uint8_t *>(pixels);
    int len = info.width * info.height * 4;
    for (int i = 0; i < len; ++i) {
        *dstPixels++ = *srcPixels++;
    }

    //释放像素数据
    AndroidBitmap_unlockPixels(env, newBitmap);

    return newBitmap;
}

}

Java端代码:

public class NativeUtils {

    static {
        System.loadLibrary("native-lib");
    }

    public static native Bitmap processImage(Bitmap bitmap);
}

使用时,可以直接调用NativeUtils中的processImage方法即可。当然,这只是一个简单的示例,实际开发中需要针对不同的图像处理需求进行修改和优化。

在上述代码中,我们使用了createBitmap函数将Mat矩阵中的数据复制到Bitmap中,其中Bitmap_Config::ARGB_8888表示Bitmap的像素格式为ARGB8888,即每个像素点占4个字节。而在Mat矩阵中,我们使用了CV格式来指定矩阵的数据类型。以下是常用的CV格式:

  • CV_8UC1 表示8位无符号单通道
  • CV_8UC2 表示8位无符号双通道
  • CV_8UC3 表示8位无符号三通道
  • CV_8UC4 表示8位无符号四通道
  • CV_32FC1 表示32位单精度浮点单通道
  • CV_32FC2 表示32位单精度浮点双通道
  • CV_32FC3 表示32位单精度浮点三通道
  • CV_32FC4 表示32位单精度浮点四通道

其中,UC表示unsigned char,即无符号字符类型;FC表示float,即浮点数类型。通道数可以根据需要自由组合,例如CV_8UC3表示8位无符号三通道数据。在Mat矩阵中,每个像素点所占的字节数由数据类型和通道数共同决定。例如,CV_8UC3类型的Mat矩阵中,每个像素点占用3个字节。在处理图像时,需要根据图像的实际情况进行不同类型的Mat矩阵的创建和处理。

setPixels()方法:

给bitmap赋像素值的方法有两种:

  1. bitmap.setPixel(int x,int y,color)此方法功能为给bitmap中的某个像素赋RGB值。

    参数
    x,y表示该像素的坐标。
    color为整型的RGB值。

  2. bitmap.setPixels(int [] pixels,int index,int stride, int x,int y,int width, int length)
    参数
    pixels数组表示像素RGB值
    index表示从数组的那里开始
    stride表示bitmap的跨宽,其中除了一行像素点的个数外还有其他信息,所以通常stride要大于width的值。
    x,y表示从bitmap的哪个坐标开始。
    width, length表示多宽多行

其中记住width*length要小于或等于pixels的数组长度,否则会抛出异常。

二维数组转化为Bitmap

//输入的数据类型可以根据需要更改
    public static Bitmap ConvertToBinaryBitmap(float[][] data,float threshold){
        int width = data[0].length;
        int height = data.length;

        //创建初始图像
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        //bitmap赋值
        int[] pixs = new int[width * height];
        
        for(int i=0;i<height;i++){
            for(int j=0;j<width;j++){
                int x = i*width+j;
                //大于阈值,设置为白色
                if(data[i][j]>threshold){
                    int r = ((pixs[x] >> 16) & 0xff)|0xff;
                    int g = ((pixs[x] >> 8) & 0xff)|0xff;
                    int b =( pixs[x] & 0xff)|0xff;
                    pixs[x] = 0xff000000 | (r << 16) | (g << 8) | b;
                } 
                //小于阈值,设置为黑色
                else {
                    pixs[x] = 0xff000000;
                }
            }
        }
        //写入图像
        result.setPixels(pixs,0,width,0,0,width,height);
        return result;
    }

Bitmap和CV::Mat的相互转化

Bitmap转化Matrix:

bool BitmapToMatrix(JNIEnv * env, jobject obj_bitmap, cv::Mat & matrix) {
    void * bitmapPixels;                                            // Save picture pixel data
    AndroidBitmapInfo bitmapInfo;                                   // Save picture parameters

    ASSERT_FALSE( AndroidBitmap_getInfo(env, obj_bitmap, &bitmapInfo) >= 0);        // Get picture parameters
    ASSERT_FALSE( bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888
                  || bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565 );          // Only ARGB? 8888 and RGB? 565 are supported
    ASSERT_FALSE( AndroidBitmap_lockPixels(env, obj_bitmap, &bitmapPixels) >= 0 );  // Get picture pixels (lock memory block)
    ASSERT_FALSE( bitmapPixels );

    if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC4, bitmapPixels);    // Establish temporary mat
        tmp.copyTo(matrix);                                                         // Copy to target matrix
    } else {
        cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC2, bitmapPixels);
        cv::cvtColor(tmp, matrix, cv::COLOR_BGR5652RGB);
    }

    //convert RGB to BGR
    cv::cvtColor(matrix,matrix,cv::COLOR_RGB2BGR);

    AndroidBitmap_unlockPixels(env, obj_bitmap);            // Unlock
    return true;
}

Matrix转化Bitmap:

bool MatrixToBitmap(JNIEnv * env, cv::Mat & matrix, jobject obj_bitmap) {
    void * bitmapPixels;                                            // Save picture pixel data
    AndroidBitmapInfo bitmapInfo;                                   // Save picture parameters

    ASSERT_FALSE( AndroidBitmap_getInfo(env, obj_bitmap, &bitmapInfo) >= 0);        // Get picture parameters
    ASSERT_FALSE( bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888
                  || bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565 );          // Only ARGB? 8888 and RGB? 565 are supported
    ASSERT_FALSE( matrix.dims == 2
                  && bitmapInfo.height == (uint32_t)matrix.rows
                  && bitmapInfo.width == (uint32_t)matrix.cols );                   // It must be a 2-dimensional matrix with the same length and width
    ASSERT_FALSE( matrix.type() == CV_8UC1 || matrix.type() == CV_8UC3 || matrix.type() == CV_8UC4 );
    ASSERT_FALSE( AndroidBitmap_lockPixels(env, obj_bitmap, &bitmapPixels) >= 0 );  // Get picture pixels (lock memory block)
    ASSERT_FALSE( bitmapPixels );

    if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC4, bitmapPixels);
        switch (matrix.type()) {
            case CV_8UC1:   cv::cvtColor(matrix, tmp, cv::COLOR_GRAY2RGBA);     break;
            case CV_8UC3:   cv::cvtColor(matrix, tmp, cv::COLOR_RGB2RGBA);      break;
            case CV_8UC4:   matrix.copyTo(tmp);                                 break;
            default:        AndroidBitmap_unlockPixels(env, obj_bitmap);        return false;
        }
    } else {
        cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC2, bitmapPixels);
        switch (matrix.type()) {
            case CV_8UC1:   cv::cvtColor(matrix, tmp, cv::COLOR_GRAY2BGR565);   break;
            case CV_8UC3:   cv::cvtColor(matrix, tmp, cv::COLOR_RGB2BGR565);    break;
            case CV_8UC4:   cv::cvtColor(matrix, tmp, cv::COLOR_RGBA2BGR565);   break;
            default:        AndroidBitmap_unlockPixels(env, obj_bitmap);        return false;
        }
    }
    AndroidBitmap_unlockPixels(env, obj_bitmap);                // Unlock
    return true;
}

CV操作

ConvertTo

convertTo函数的用法

void Mat::convertTo( Mat& m, int rtype, double alpha=1, double beta=0 )
const;

输入参数:
m 目标矩阵。如果m的大小与原矩阵不一样,或者数据类型与参数不匹配,那么在函数convertTo内部会先给m重新分配空间。
rtype 指定从原矩阵进行转换后的数据类型,即目标矩阵m的数据类型。当然,矩阵m的通道数应该与原矩阵一样的。如果rtype是负数,那么m矩阵的数据类型应该与原矩阵一样。
alpha 缩放因子。默认值是1。即把原矩阵中的每一个元素都乘以alpha。
beta 增量。默认值是0。即把原矩阵中的每一个元素都乘以alpha,再加上beta。

功能:
把一个矩阵从一种数据类型转换到另一种数据类型,同时可以带上缩放因子和增量,公式如下:

m(x,y)=saturate_cast<rType>(alpha*(*this)(x,y)+beta);

由于有数据类型的转换,所以需要用saturate_cast来处理数据的溢出。文章来源地址https://www.toymoban.com/news/detail-405938.html

到了这里,关于安卓Android Studio JNI开发问题澄清与汇总的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android和JNI交互 : 常见的图像格式转换 : NV21、RGBA、Bitmap等

    最近在使用 OpenCV 处理图片的时候,经常会遇到需要转换图像的情况,网上相关资料比较少,也不全,有时候得费劲老半天才能搞定。 自己踩了坑后,在这里记录下,都是我在项目中遇到的图像转化操作,是一些常用的图像格式转换操作。 具体包括: nv21、rgba、rgb 转换 OpenC

    2024年02月05日
    浏览(35)
  • Android JNI和原生交互,常见的图像格式转换 : NV21、RGBA、Bitmap等

    最近在使用 OpenCV 处理图片的时候,经常会遇到需要转换图像的情况,网上相关资料比较少,也不全,有时候得费劲老半天才能搞定。 自己踩了坑后,在这里记录下,都是我在项目中遇到的图像转化操作,是一些常用的图像格式转换操作。 具体包括: nv21、rgba、rgb 转换 OpenC

    2024年02月06日
    浏览(33)
  • Android问题笔记四十三:JNI 开发如何快速定位崩溃问题

    Unity3D特效百例 案例项目实战源码 Android-Unity实战问题汇总 游戏脚本-辅助自动化 Android控件全解手册 再战Android系列 Scratch编程案例 软考全系列 Unity3D学习专栏 蓝桥系列 ChatGPT和AIGC 专注于 Android/Unity 和各种游戏开发技巧,以及 各种资源分享 (网站、工具、素材、源码、游戏等

    2024年02月05日
    浏览(35)
  • APP安卓开发之Android Studio从安装到创建项目(一键解决gradle下载缓慢以及写代码没提示问题,包含如何创建手机模拟器)教程

    选择NEXT 选择NEXT 选择要安装的地址,然后选择NEXT 选择Install 先启动刚安装好的Android Studio 选择Do not import settings,然后选择OK 选择Cancel 先选择D\\\'ont send,然后选择NEXT 这里选择Custom,然后NEXT 选择Android Studio自带JDK的安装位置,然后NEXT 选择一个自己喜欢的主题颜色,然后NEXT 选

    2024年04月29日
    浏览(55)
  • Android Studio 进行NDK开发,实现JNI,以及编写C++与Java交互(Java调用本地函数)并编译出本地so动态库

    1.首先认识一下NDK。 (1)什么是NDK? NDK全称是Native Development Kit,NDK提供了一系列的工具,帮助开发者快速开发C/C++的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,

    2024年02月11日
    浏览(35)
  • Android Studio安卓开发--ListView学习整理

    ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。 (1)activity_main.xml布局中加入ListView控件:(先占满整个布局的空间) (2)MainActivity.java中使用ListView展示大量数据: 使用ArrayAdapter泛型类(指定为String)将数据

    2024年01月20日
    浏览(37)
  • Android Studio安卓开发-RecycleView新闻栏设计

    在上一博客中,我们完成类微信UI开发,在此基础上,在联系人界面实现RecycleView的简单用例,在发现界面实现RecycleView的流式布局。如下图所示。 对于RecycleView的基础布局学习我们先到这,现在需要我们对每一个RecycleView的Item实现点击操作,能够跳转至Item的详情界面,下面我

    2024年02月16日
    浏览(32)
  • mac端安卓开发环境(Android studio)配置

    我这里安装版本为java16。一共两种安装方法,从官网手动安装或使用简易方式安装。 手动安装 先从[Oracle官网]https://www.oracle.com/java/technologies/javase-downloads.html下载java 将下载文件夹copy至目标文件夹 cp java16 /Library/Java/JavaVirtualMachines/ 配置环境变量, open -e ~/.bash_profile , 在文件中

    2024年02月10日
    浏览(39)
  • 升级Android Studio Electric Eel问题汇总

    1.升级以后找不到java可执行程序 问题原因:升级后,Android Studio自带的java目录不再是根目录/jre,调整为一个新目录 Studio根目录/jbr 修改方法:1)修改系统环境变量, JAVA_HOME调整为Studio下对应的java根目录jbr。 2)Android Studio中的编译环境调整 File--Settings--Build、Execution、Devel

    2023年04月21日
    浏览(28)
  • 安卓开发 微信ui界面设计 (Android Studio)

    功能: 开发一个类似微信的主页面框架,UI布局为上中下结构,包含4个tab界面: 开发技术为: layout xml、控件、监听,fragment; 设计流程: 创建项目 改下项目名,编程语言为java UI界面 UI界面由多个xml组成,头部标题为微信,中间留空白,底部分为四个(微信,联系人,发现,

    2024年02月15日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包