java 如何讀圖 怎樣傳給 C++

有读者问到 “”“从安卓模拟器路径用opencv读取图像失败”,您这个问题解决了吗?”

我刚开始将c++算法嵌入到安卓或java的时候也遇到过这个基本的问题,因为两者机制不一样,很容易搞混。

在安卓中是不能直接用opencv的imread函数的,必须以安卓自己的方式读图,然后将buffer传递给接口函数。我的算法接口用了jni封装,下面做个一简单的例子进行示例说明,希望对像我这样的安卓初学者有点帮助。

 

java读图并转换到字节数组中

 

方式一: 从res文件夹读取(传入c++接口有问题)

/*

* test_image为图像的名称, 测试图像放在app\src\main\res\drawable文件夹下

*/

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);

int height = bitmap.getHeight();

int width = bitmap.getWidth();

byte[] data = bitmap.getNinePatchChunk();

 

进入c++函数后,测试一下data数组是否正确,不行的话就用下面的转换一下(将Bitmap对象读到字节数组中):

ByteArrayOutputStream baos = new ByteArrayOutputStream();

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

byte[] datas = baos.toByteArray();

 

存在一个问题: 默认读入的图像格式是ARGB_8888类型,且每个通道占1个byte

 

方式二:从assets文件夹读取(传入c++接口测试ok, 与VS中的结果一致)

/*

* images/lena_gray.jpg , 测试图像放在app\src\main\assets\images文件夹下

* 用到的接口函数为ReadImageFromLocal

*/

package com.example.builtinalgorithm;

import androidx.appcompat.app.AppCompatActivity;

import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'textdetection-lib' library on application startup.
    //static {
    //    System.loadLibrary("textdetection-lib");
    //}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = stringFromJNI();

        AssetManager assetManager = getAssets();
        String[] files = null;
        try {
            //files = assetManager.list("image"); //image 表示assets文件夹下的子文件夹名称
            files = assetManager.list("");
        } catch (IOException e) {
            Log.e("tag", e.getMessage());
            str += e.getMessage();
            str += "\n";
        }

        //InputStream in = getAssets().open("file:///android_asset/frozen_east_text_detection.pb");
        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);

        String assetFile = "file number is: " + Integer.toString (files.length) +" First file name is: "+ files[0] + "\n";
        str += assetFile;
        assetFile = "file number is: " + Integer.toString (files.length) +" Second file name is: "+ files[1] + "\n";
        str += assetFile;
        assetFile = "file number is: " + Integer.toString (files.length) +" Third file name is: "+ files[2] + "\n";
        str += assetFile;

        //str += ReadNetFromLocal(files[0]); //F:/text_detect/models/east/frozen_east_text_detection.pb "file:///android_asset/frozen_east_text_detection.pb"
        //Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lena_gray);
        InputStream inputStream = null;
        try {
            inputStream = getResources().getAssets().open("images/lena_gray.jpg");
        } catch (IOException e) {
            e.printStackTrace();
            str += e.getMessage();
            str += "\n";
        }
        // 直接读取 ARGB_8888 占4个byte
        //Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
        // 灰度图像只需要一个通道表示:转换为一个通道,占1byte,这时只有alpha通道
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ALPHA_8;
        Rect rect = new Rect();
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream, rect, options);
        // lena_gray.jpg大小为512*512,第一个像素值为163
        int height = bitmap.getHeight();
        int width = bitmap.getWidth();
        int color = bitmap.getPixel(0,0);
        int a = Color.alpha(color);
        int bytes = bitmap.getByteCount();
        str += Integer.toString(width) + " " + Integer.toString(height) +" " + Integer.toString(bytes) +" " + Integer.toString(a) + "\n";
        
        // Bitmap转换为byte[]
        ByteBuffer buf = ByteBuffer.allocate(bytes);
        bitmap.copyPixelsToBuffer(buf);
        byte[] datas = buf.array();
        str += Integer.toString(datas.length) + "\n";
        str += ReadImageFromLocal(datas, width, height,1);

        tv.setText(str);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public native String ReadNetFromLocal(String path);
    public native String ReadImageFromLocal(byte[] imgdata, int width, int height, int channels);

 

下面展示一下native-cpp中的接口函数。这部分是用来测试传入的buffer是否正确。主要查看通道、pixel,然后对传入的buffer进行简单的均值方差计算,验证与c++版本下的结果是否一样即可。

#include <jni.h>
#include <string>

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
using namespace cv::dnn;

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_builtinalgorithm_MainActivity_ReadImageFromLocal(
        JNIEnv *env,
        jobject /* this */, jbyteArray imgdata, jint width, jint height, jint channels) {
//    jboolean iscopy;
//    const char* nativeString = env->GetStringUTFChars(js, &iscopy);
//    string file(nativeString);
    std::string tips = "In cpp function: \n";
    int ch= channels;
    int cols = width;
    int rows = height;
    jsize len = env->GetArrayLength(imgdata);
    tips += "GetArrayLength: ";
    tips += to_string((int)len);
    tips += "\n";
//    jbyte *jbarray = (jbyte *)malloc(len * sizeof(jbyte));
//    env->GetByteArrayRegion(imgdata, 0, len, jbarray);
    jbyte* jbarray = env->GetByteArrayElements(imgdata,0);
    unsigned char *dDate = (unsigned char*)jbarray;

    try {
        //Mat img = imread(file);
        Mat img;
        int type = CV_8UC1;
        if(ch==3){
            type = CV_8UC3;
            Mat tmp(rows,cols,type,dDate);
            cvtColor(tmp,img,COLOR_RGB2GRAY);
        }
        else if(ch==1){
            type = CV_8UC1;
            Mat tmp(rows,cols,type,dDate);
            img = tmp;
        }
        else if(ch==4){
            type = CV_8UC4;
            Mat tmp(rows,cols,type,dDate);
            cvtColor(tmp,img,COLOR_RGBA2GRAY);
        }
        else{
            tips += "param:channels is error";
            return env->NewStringUTF(tips.c_str());
        }

        tips += to_string(cols);
        tips += "  ";
        tips += to_string(rows);
        tips += "  ";
        int pixl = *(img.ptr<uchar>(0)+0);
        tips += to_string(pixl);
        tips += "\n";
        Scalar a,b;
        meanStdDev(img, a,b);
        tips += "Load image is ok: ";
        tips += to_string(a[0]);
        tips += "  ";
        tips += to_string(b[0]);
        tips += "\n";
    }catch(cv::Exception e)
    {
        String error = e.msg;
        tips += error;
        tips += "Load image error. \n";
    }

    return env->NewStringUTF(tips.c_str());
}

关于CMakeList.txt中的opencv配置这里再重复一遍,我当前用的native-lib名称改了一下:textdetection-lib,其他出现opencv字眼的地方都是opencv的配置

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# 2019.10.31
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(opencv_411_dir E:/opencv-4.1.1-android-sdk/OpenCV-android-sdk/sdk/native/jni)
set(app_dir F:/android/AndroidStudioProjects/BuiltinAlgorithm/app)

include_directories(${opencv_411_dir}/include)
add_library(opencv-lib SHARED IMPORTED)
set_target_properties(opencv-lib PROPERTIES IMPORTED_LOCATION ${app_dir}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java4.so)


# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        textdetection-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        textdetection-lib.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        textdetection-lib
        opencv-lib #2019.10.31

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值