这里要演示的是使用Android studio 做APP开发,使用JNI与C++交互的demo。
1.创建一个Native C++工程。
2.命令工程和指定交互语言。
3.指定C++ 语法版本。
4.创建完成之后打开cpp目录下的CMakeLists.txt文件,这里有IDE默认生成的链接路径。
5.把编译好的opencv库(ndk r21d,android api 24)复制到CPP目录下,添加依赖。(我这里用的OpenCV是nihui大佬的opencv-mobile,因为小(不到20M)而且不用自己编译)。
1.首先在main.xml布局文件添加控件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
ImageView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_open_images"
android:layout_width="0dp"
android:text="打开图像"
android:layout_height="wrap_content"
android:layout_weight="1">
Button>
<Button
android:id="@+id/btn_gray_image"
android:layout_width="0dp"
android:text="处理图像"
android:layout_height="wrap_content"
android:layout_weight="1">
Button>
<Button
android:id="@+id/btn_send_image"
android:layout_width="0dp"
android:text="交互图像"
android:layout_height="wrap_content"
android:layout_weight="1">
Button>
LinearLayout>>
LinearLayout>
2.添加一个Java类用来写交互接口
2.添加两个接口, 一个是本地读取图像,一个是从资源里面读取图像。
3.MainActivity.java的代码:
package com.dashu.dashuaiip;
import java.io.InputStream;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MainActivity<bitmap2> extends Activity
{
private static final int SELECT_IMAGE = 1;
private ImageView imageView;
private Bitmap bitmap = null;
private Bitmap temp = null;
private Bitmap showImage = null;
private Bitmap bitmapCopy = null;
private Bitmap dst = null;
boolean useGPU = true;
DaShuAPI dashuapi = new DaShuAPI();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView = (ImageView) findViewById(R.id.image_view);
//初始化模板
try
{
initTemplate();
Log.e("MainActivity", "init template file ok!");
} catch (IOException e) {
Log.e("MainActivity", "init template file error!");
}
//打开图像
Button openFile = (Button) findViewById(R.id.btn_open_images);
openFile.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View arg0)
{
Intent i = new Intent(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i, SELECT_IMAGE);
}
});
Button image_gray = (Button) findViewById(R.id.btn_gray_image);
image_gray.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View arg0)
{
if (showImage == null)
{
return;
}
Bitmap bitmap = dashuapi.grayModel(showImage);
imageView.setImageBitmap(bitmap);
}
});
Button read_assets_image = (Button) findViewById(R.id.btn_send_image);
read_assets_image.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View arg0)
{
if (showImage == null)
{
return;
}
Bitmap bitmap = dashuapi.readAssetsImage();
imageView.setImageBitmap(bitmap);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
try
{
if (requestCode == SELECT_IMAGE) {
bitmap = decodeUri(selectedImage);
showImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);
bitmapCopy = bitmap.copy(Bitmap.Config.ARGB_8888, true);
imageView.setImageBitmap(bitmap);
}
}
catch (FileNotFoundException e)
{
Log.e("MainActivity", "FileNotFoundException");
return;
}
}
}
private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
{
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 640;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
// Rotate according to EXIF
int rotate = 0;
try
{
ExifInterface exif = new ExifInterface(getContentResolver().openInputStream(selectedImage));
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
}
catch (IOException e)
{
Log.e("MainActivity", "ExifInterface IOException");
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
private void initTemplate() throws IOException
{
//用io流读取二进制文件,最后存入到byte[]数组中
InputStream in = getAssets().open("template.jpg");//模板图像文件
int length = in.available();
byte[] buffer = new byte[length];
in.read(buffer);
//转换为Bitmap
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap template = BitmapFactory.decodeByteArray(buffer, 0, buffer.length, opts);
int width = template.getWidth();
int height = template.getHeight();
int[] pixArr = new int[width*height];
template.getPixels(pixArr,0,width,0,0,width,height);
int rt = dashuapi.sendTemplate(pixArr,width,height);
}
}
4.jni.cpp的代码
#include
#include
#include
#include
#include
cv::Mat cv_template;
void BitmapToMat2(JNIEnv *env, jobject& bitmap, cv::Mat& mat, jboolean needUnPremultiplyAlpha)
{
AndroidBitmapInfo info;
void *pixels = 0;
cv::Mat &dst = mat;
try {
CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
info.format == ANDROID_BITMAP_FORMAT_RGB_565);
CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
CV_Assert(pixels);
dst.create(info.height, info.width, CV_8UC4);
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
if (needUnPremultiplyAlpha) cvtColor(tmp, dst, cv::COLOR_mRGBA2RGBA);
else tmp.copyTo(dst);
} else {
// info.format == ANDROID_BITMAP_FORMAT_RGB_565
cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
cvtColor(tmp, dst, cv::COLOR_BGR5652RGBA);
}
AndroidBitmap_unlockPixels(env, bitmap);
return;
} catch (const 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;
} catch (...) {
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");
return;
}
}
void BitmapToMat(JNIEnv *env, jobject& bitmap, cv::Mat& mat) {
BitmapToMat2(env, bitmap, mat, false);
}
void MatToBitmap2
(JNIEnv *env, cv::Mat& mat, jobject& bitmap, jboolean needPremultiplyAlpha)
{
AndroidBitmapInfo info;
void *pixels = 0;
cv::Mat &src = mat;
try {
CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
info.format == ANDROID_BITMAP_FORMAT_RGB_565);
CV_Assert(src.dims == 2 && info.height == (uint32_t) src.rows &&
info.width == (uint32_t) src.cols);
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);
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::COLOR_GRAY2RGBA);
}
else if (src.type() == CV_8UC3)
{
cvtColor(src, tmp, cv::COLOR_RGB2RGBA);
}
else if (src.type() == CV_8UC4)
{
if (needPremultiplyAlpha)
{
cvtColor(src, tmp, cv::COLOR_RGBA2mRGBA);
}
else{
src.copyTo(tmp);
}
}
} else {
// info.format == ANDROID_BITMAP_FORMAT_RGB_565
cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
if (src.type() == CV_8UC1)
{
cvtColor(src, tmp, cv::COLOR_GRAY2BGR565);
}
else if (src.type() == CV_8UC3)
{
cvtColor(src, tmp, cv::COLOR_RGB2BGR565);
}
else if (src.type() == CV_8UC4)
{
cvtColor(src, tmp, cv::COLOR_RGBA2BGR565);
}
}
AndroidBitmap_unlockPixels(env, bitmap);
return;
}catch (const 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;
} catch (...) {
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
return;
}
}
jobject generateBitmap(JNIEnv *env, uint32_t width, uint32_t height)
{
jclass bitmapCls = env->FindClass("android/graphics/Bitmap");
jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls,
"createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jstring configName = env->NewStringUTF("ARGB_8888");
jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(
bitmapConfigClass, "valueOf",
"(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass,
valueOfBitmapConfigFunction, configName);
jobject newBitmap = env->CallStaticObjectMethod(bitmapCls,createBitmapFunction,
width,
height, bitmapConfig);
return newBitmap;
}
void MatToBitmap(JNIEnv *env, cv::Mat& mat, jobject& bitmap)
{
MatToBitmap2(env, mat, bitmap, false);
}
extern "C" JNIEXPORT jobject JNICALL
Java_com_dashu_dashuaiip_DaShuAPI_grayModel(JNIEnv *env,jobject, jobject image)
{
cv::Mat cv_src,cv_gray;
//bitmap转化成mat
BitmapToMat(env,image,cv_src);
cv::cvtColor(cv_src,cv_gray,cv::COLOR_BGRA2GRAY);
MatToBitmap(env,cv_gray,image);
return image;
}
extern "C" JNIEXPORT jobject JNICALL
Java_com_dashu_dashuaiip_DaShuAPI_readAssetsImage(JNIEnv *env,jobject)
{
jobject dst = generateBitmap(env,cv_template.cols,cv_template.rows);
MatToBitmap(env,cv_template,dst);
return dst;
}
extern "C"
JNIEXPORT int JNICALL
Java_com_dashu_dashuaiip_DaShuAPI_sendTemplate(JNIEnv *env, jobject instance, jintArray pix_, jint w, jint h)
{
jint *pix = env->GetIntArrayElements(pix_, NULL);
if (pix == NULL)
{
return -1;
}
//将c++图片转成Opencv图片
cv::Mat cv_temp(h, w, CV_8UC4, (unsigned char *) pix);
if(cv_temp.empty())
{
return -2;
}
cv::cvtColor(cv_temp,cv_template,cv::COLOR_BGRA2BGR);
return 0;
}