![【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第1頁](http://file4.renrendoc.com/view/381388f39e392764774f1b8a10d6e49b/381388f39e392764774f1b8a10d6e49b1.gif)
![【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第2頁](http://file4.renrendoc.com/view/381388f39e392764774f1b8a10d6e49b/381388f39e392764774f1b8a10d6e49b2.gif)
![【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第3頁](http://file4.renrendoc.com/view/381388f39e392764774f1b8a10d6e49b/381388f39e392764774f1b8a10d6e49b3.gif)
![【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第4頁](http://file4.renrendoc.com/view/381388f39e392764774f1b8a10d6e49b/381388f39e392764774f1b8a10d6e49b4.gif)
![【移動應(yīng)用開發(fā)技術(shù)】如何基于Android studio3.6的JNI教程之ncnn之語義分割ENet_第5頁](http://file4.renrendoc.com/view/381388f39e392764774f1b8a10d6e49b/381388f39e392764774f1b8a10d6e49b5.gif)
版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度毛竹綜合利用購銷合同-多功能產(chǎn)品交易合同范本
- 2025年度健康醫(yī)療項目合同履行擔(dān)保書規(guī)范
- 2025年度工業(yè)園區(qū)場地租賃合同
- 2025年度卡片銷售與供應(yīng)鏈管理服務(wù)合同
- 2025年度光伏電站項目融資租賃合同范本
- 2025年度企業(yè)并購過橋資金借款合同
- 2025年專用挖掘設(shè)備采購合同書
- 2025年度建筑防水工程滲漏檢測與維修服務(wù)合同
- 2025年度企業(yè)員工健康管理與兼職校醫(yī)服務(wù)合同
- 2025年度IT設(shè)備采購及售后服務(wù)合同
- 渤海大學(xué)《大數(shù)據(jù)分析與實踐》2023-2024學(xué)年期末試卷
- 2024版2024年《咚咚鏘》中班音樂教案
- GA 2139-2024警用防暴臂盾
- DL∕T 5810-2020 電化學(xué)儲能電站接入電網(wǎng)設(shè)計規(guī)范
- 北京三甲中醫(yī)疼痛科合作方案
- QCT957-2023洗掃車技術(shù)規(guī)范
- 新外研版高中英語選擇性必修1單詞正序英漢互譯默寫本
- 自愿斷絕父子關(guān)系協(xié)議書電子版
- 2023年4月自考00504藝術(shù)概論試題及答案含解析
- 美麗的大自然(教案)2023-2024學(xué)年美術(shù)一年級下冊
- 成都特色民俗課件
評論
0/150
提交評論