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

下載本文檔

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

文檔簡(jiǎn)介

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

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

->工程名enet->c++11(2)app/src/cpp下面增加opencv和ncnn的頭文件,include(3)app/src/main下面增加ncnn和opencv的靜態(tài)庫(kù)文件和動(dòng)態(tài)庫(kù)文件,(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類(lèi),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實(shí)現(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àn)閳D像預(yù)處理每個(gè)網(wǎng)絡(luò)層輸入的數(shù)據(jù)格式不一樣一般為300*300

128*128等等所以這類(lèi)需要一個(gè)resize的操作可以在cpp中寫(xiě),也可以是java讀入圖片時(shí)有個(gè)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類(lèi)型

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ù)組

長(zhǎng)度為

output_wsize

*

output_hsize,如果只是ouput_size相當(dāng)于只有一行的out的數(shù)據(jù)那就是一個(gè)object檢測(cè)數(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)用實(shí)現(xiàn),public

class

MainActivity

extends

AppCompatActivity

{

private

ENET

enet

=

new

ENET();

//java接口實(shí)例化下面直接利用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

一一對(duì)應(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();//檢測(cè)+view畫(huà)圖

}

//

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流讀取二進(jìn)制文件,最后存入到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流讀取二進(jìn)制文件,最后存入到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));

//

畫(huà)布配置

Canvas

canvas

=

new

Canvas(input_bmp);

//圖像上畫(huà)矩形

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++){

//

畫(huà)框

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

最新文檔

評(píng)論

0/150

提交評(píng)論