【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第1頁
【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第2頁
【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第3頁
【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第4頁
【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

【移動應(yīng)用開發(fā)技術(shù)】如何基于Androidstudio3.6的JNI教程之ncnn之語義分割ENet

在下給大家分享一下如何基于Androidstudio3.6的JNI教程之ncnn之語義分割ENet,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!Android是一種基于Linux內(nèi)核的自由及開放源代碼的操作系統(tǒng),主要使用于移動設(shè)備,如智能手機和平板電腦,由美國Google公司和開放手機聯(lián)盟領(lǐng)導(dǎo)及開發(fā)。本代碼可以在模擬器下進行跑。環(huán)境:Androidstudio3.6Sdk:android10api29Ndk:r15cNcnn:20200226Opencv:Opencv3.4.1androidsdkLinux下的代碼測試:mkdirbuildcdbuildcmake..make./enetmkdirbuildcdbuildcmake..make./enet運行效果,Android開始:(1)新建工程,New->NewProject->選擇Nativec++

->工程名enet->c++11(2)app/src/cpp下面增加opencv和ncnn的頭文件,include(3)app/src/main下面增加ncnn和opencv的靜態(tài)庫文件和動態(tài)庫文件,(4)app/src/main下面增加模型文件assets(5)修改布局文件,app/src/main/res/layout/activity_main.xml<?xml

version="1.0"

encoding="utf-8"?>

<RelativeLayout

xmlns:android="/apk/res/android"

xmlns:app="/apk/res-auto"

xmlns:tools="/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity">

<LinearLayout

android:id="@+id/btn_ll"

android:layout_alignParentBottom="true"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

<Button

android:id="@+id/use_photo"

android:layout_weight="1"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:text="選圖"/>

<Button

android:id="@+id/detect_photo"

android:layout_weight="1"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:text="分割"/>

</LinearLayout>

<ImageView

android:id="@+id/show_image"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_above="@id/btn_ll"

android:layout_alignParentTop="true"

android:layout_marginTop="1dp"

android:layout_marginBottom="-1dp"

/>

</RelativeLayout>(6)app/src/main/java/com/example/enet增加ENET類,public

class

ENET

{

public

native

boolean

Init(byte[]

param,

byte[]

bin);

public

native

float[]

Process(Bitmap

bitmap);

//

Used

to

load

the

'native-lib'

library

on

application

startup.

static

{

System.loadLibrary("ENET");

}

}(7)app/src/main/cpp/enet-jni.cpp實現(xiàn)其jni方法,extern

"C"

JNIEXPORT

jboolean

JNICALL

Java_com_example_enet_ENET_Init(JNIEnv

*env,

jobject

thiz,

jbyteArray

param,

jbyteArray

bin)

{

//

TODO:

implement

Init()

ncnn::Mat

ncnn_param;

ncnn::Mat

ncnn_bin;

//

init

param

{

int

len

=

env->GetArrayLength(param);

ncnn_param.create(len,

(size_t)

1u);

env->GetByteArrayRegion(param,

0,

len,

(jbyte

*)

ncnn_param);

}

//

init

bin

{

int

len

=

env->GetArrayLength(bin);

ncnn_bin.create(len,

(size_t)

1u);

env->GetByteArrayRegion(bin,

0,

len,

(jbyte

*)

ncnn_bin);

}

ncnn_net

=

new

ENET(ncnn_param,ncnn_bin);

return

JNI_TRUE;

}

extern

"C"

JNIEXPORT

jfloatArray

JNICALL

Java_com_example_enet_ENET_Process(JNIEnv

*env,

jobject

thiz,

jobject

bitmap)

{

//

TODO:

implement

Process()

//

ncnn

from

bitmap

ncnn::Mat

in;

{

AndroidBitmapInfo

info;

AndroidBitmap_getInfo(env,

bitmap,

&info);

int

width

=

info.width;

int

height

=

info.height;

if

(info.format

!=

ANDROID_BITMAP_FORMAT_RGBA_8888)

return

NULL;

void*

indata;

AndroidBitmap_lockPixels(env,

bitmap,

&indata);

//

把像素轉(zhuǎn)換成data,并指定通道順序

//

因為圖像預(yù)處理每個網(wǎng)絡(luò)層輸入的數(shù)據(jù)格式不一樣一般為300*300

128*128等等所以這類需要一個resize的操作可以在cpp中寫,也可以是java讀入圖片時有個resize操作

//in

=

ncnn::Mat::from_pixels_resize((const

unsigned

char*)indata,

ncnn::Mat::PIXEL_RGBA2RGB,

width,

height,300,300);

in

=

ncnn::Mat::from_pixels(static_cast<const

unsigned

char

*>(indata),

ncnn::Mat::PIXEL_RGBA2BGR,

width,

height);

//

下面一行為debug代碼

__android_log_print(ANDROID_LOG_DEBUG,

"ENetJniIn",

"enet_process_has_input1,

in.w:

%d;

in.h:

%d

in.c:%d

",

in.w,

in.h,in.c);

//AndroidBitmap_unlockPixels(env,

bitmap);

}

{

ncnn::Mat

out

=

ncnn_net->process(in);

__android_log_print(ANDROID_LOG_DEBUG,

"ENetJniIn",

"enet_process_has_output,

in.w:

%d;

in.h:

%d

in.c:%d

",

out.w,

out.h,out.c);

int

output_wsize

=

out.w;

int

output_hsize

=

out.h;

//輸出整理

float

*output[output_wsize

*

output_hsize];

//

float類型

for(int

i

=

0;

i<

out.h;

i++)

{

for

(int

j

=

0;

j

<

out.w;

j++)

{

output[i*output_wsize

+

j]

=

&out.row(

i)[j];

}

}

//建立float數(shù)組

長度為

output_wsize

*

output_hsize,如果只是ouput_size相當(dāng)于只有一行的out的數(shù)據(jù)那就是一個object檢測數(shù)據(jù)

jfloatArray

jOutputData

=

env->NewFloatArray(output_wsize

*

output_hsize);

if

(jOutputData

==

nullptr)

return

nullptr;

env->SetFloatArrayRegion(jOutputData,

0,

output_wsize

*

output_hsize,

reinterpret_cast<const

jfloat

*>(*output));

return

jOutputData;

}

}(8)app/src/main/java/com/example/enet中MainActivity做具體的調(diào)用實現(xiàn),public

class

MainActivity

extends

AppCompatActivity

{

private

ENET

enet

=

new

ENET();

//java接口實例化下面直接利用java函數(shù)調(diào)用NDK

c++函數(shù)

private

Bitmap

yourSelectedImage

=

null;

private

static

final

int

SELECT_IMAGE

=

1;

private

static

final

String

TAG

=

MainActivity.class.getName();

private

ImageView

show_image;

private

boolean

load_result

=

false;

private

int[]

ddims

=

{1,

3,

512,

288};

//這里的維度的值要和train

model的input

一一對應(yīng)

@Override

protected

void

onCreate(Bundle

savedInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

try

{

initENet();//初始化模型

Log.e("MainActivity",

"initENet

ok");

}

catch

(IOException

e)

{

Log.e("MainActivity",

"initENet

error");

}

init_view();//檢測+view畫圖

}

//

initialize

view

private

void

init_view()

{

show_image

=

(ImageView)

findViewById(R.id.show_image);

Button

use_photo

=

(Button)

findViewById(R.id.use_photo);

use_photo.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

detect_photo

=

(Button)

findViewById(R.id.detect_photo);

detect_photo.setOnClickListener(new

View.OnClickListener()

{

@Override

public

void

onClick(View

arg0)

{

if

(yourSelectedImage

==

null)

return;

predict_image(yourSelectedImage);

}

});

}

private

void

initENet()

throws

IOException

{

byte[]

param

=

null;

byte[]

bin

=

null;

{

//用io流讀取二進制文件,最后存入到byte[]數(shù)組中

InputStream

assetsInputStream

=

getAssets().open("enet_512288.param.bin");//

param:

網(wǎng)絡(luò)結(jié)構(gòu)文件

int

available

=

assetsInputStream.available();

param

=

new

byte[available];

int

byteCode

=

assetsInputStream.read(param);

assetsInputStream.close();

}

{

//用io流讀取二進制文件,最后存入到byte上,轉(zhuǎn)換為int型

InputStream

assetsInputStream

=

getAssets().open("enet_512288.bin");//bin:

model文件

int

available

=

assetsInputStream.available();

bin

=

new

byte[available];

int

byteCode

=

assetsInputStream.read(bin);

assetsInputStream.close();

}

load_result

=

enet.Init(param,

bin);//

再將文件傳入java的NDK接口(c++

代碼中的init接口

)

Log.d("load

model",

"ENet_load_model_result:"

+

load_result);

}

@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

bitmap

=

decodeUri(selectedImage);

Bitmap

rgba

=

bitmap.copy(Bitmap.Config.ARGB_8888,

true);

//

resize

to

512x288

yourSelectedImage

=

Bitmap.createScaledBitmap(rgba,

ddims[2],

ddims[3],

false);

show_image.setImageBitmap(yourSelectedImage);

}

}

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

=

600;

//

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;

return

BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage),

null,

o2);

}

//

predict

image

private

void

predict_image(Bitmap

bmp)

{

//

picture

to

float

array

Bitmap

rgba

=

bmp.copy(Bitmap.Config.ARGB_8888,

true);

//

resize

Bitmap

input_bmp

=

Bitmap.createScaledBitmap(rgba,

ddims[2],

ddims[3],

false);

try

{

//

Data

format

conversion

takes

too

long

//

Log.d("inputData",

Arrays.toString(inputData));

long

start

=

System.currentTimeMillis();

//

get

predict

result

float[]

result

=

enet.Process(input_bmp);

//

time

end

long

end

=

System.currentTimeMillis();

Log.d(TAG,

"origin

predict

result:"

+

Arrays.toString(result));

long

time

=

end

-

start;

Log.d("result

length",

"length

of

result:

"

+

String.valueOf(result.length));

//

畫布配置

Canvas

canvas

=

new

Canvas(input_bmp);

//圖像上畫矩形

Paint

paint

=

new

Paint();

//continue

to

draw

rect

Log.d(TAG,

"result

:"

+

result.length);

Log.d(TAG,

"result

:"

+

Arrays.toString(result));

for(int

num

=

0;

num

<

result.length;

num++){

//

畫框

int

row

=num%ddims[2];

int

col

=

num/ddims[2];

if

(result[num]==1){

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.STROKE);//不填充

canvas.drawCircle(row,

col,

1,

paint);

}

if

(result[num]==2){

paint.setColor(Color.BLUE);

paint.setStyle(Paint.Style.STROKE);//不填充

canvas.drawCircle(row,

col,

1,

paint);

}

if

(result[num]==3){

paint.setColor(Color.GREEN);

paint.setStyle(Paint.Style.STROKE);//不填充

canvas.drawCircle(row,

col,

1,

paint);

}

}

show_image.setImageBitmap(input_bmp);

}

catch

(Exception

e)

{

e.printStackTrace();

}

}

}(9)app/src/main/cpp下面修改CMakeListscmake_minimum_required(VERSION

3.4.1)

include_directories(include)

file(GLOB

ENET_SRC

*.h

*.cpp)

set(ENET_COMPILE_CODE

${ENET_SRC})

add_library(libopencv_java3

SHARED

IMPORTED)

set_target_properties(libopencv_java3

PROPERTIES

IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java3.so)

add_library(libncnn

STATIC

IMPORTED

)

set_target_properties(libncnn

PROPERTIES

IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libncnn.a)

add_library(

#

Sets

the

name

of

the

library.

ENET

##

為生成.so的文字最好直接和.c名字一樣,需要更改

#

Sets

the

library

as

a

shared

library.

SHARED

#

Provides

a

relati

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論