Skip to content

Commit

Permalink
add android Demo project
Browse files Browse the repository at this point in the history
  • Loading branch information
Postroggy committed Dec 26, 2024
1 parent 887a1c3 commit 45d7774
Show file tree
Hide file tree
Showing 625 changed files with 223,956 additions and 0 deletions.
11 changes: 11 additions & 0 deletions android-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
app/.cxx
app/release
/captures
.externalNativeBuild
.cxx
local.properties
2 changes: 2 additions & 0 deletions android-demo/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build
.cxx
47 changes: 47 additions & 0 deletions android-demo/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
plugins {
alias(libs.plugins.android.application)
}

android {
namespace 'com.gyq.yolov8'
compileSdk 34

defaultConfig {
applicationId "com.gyq.yolov8"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
externalNativeBuild {
cmake {
version "3.31.1" // 确保你的CMake版本是正确的
path file('src/main/jni/CMakeLists.txt')
}
}
ndkVersion "25.2.9519653"
}

dependencies {

implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}
21 changes: 21 additions & 0 deletions android-demo/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
22 changes: 22 additions & 0 deletions android-demo/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<!-- 申请相机使用权限 -->
<uses-permission android:name="android.permission.CAMERA" />

<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera" />

<application android:label="@string/app_name">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Binary file added android-demo/app/src/main/assets/yolov8n.bin
Binary file not shown.
199 changes: 199 additions & 0 deletions android-demo/app/src/main/assets/yolov8n.param

Large diffs are not rendered by default.

Binary file added android-demo/app/src/main/assets/yolov8s.bin
Binary file not shown.
199 changes: 199 additions & 0 deletions android-demo/app/src/main/assets/yolov8s.param

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions android-demo/app/src/main/java/com/gyq/yolov8/MainActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.gyq.yolov8;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Spinner;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;


public class MainActivity extends Activity implements SurfaceHolder.Callback {
public static final int REQUEST_CAMERA = 100; // note: 状态请求码(常量)


private Yolov8Ncnn yolov8ncnn = new Yolov8Ncnn(); // Yolov8Ncnn 对象,用于加载模型并进行推理处理
private int facing = 0; // 标志摄像头的前置或者后置

private Spinner spinnerModel; // 主界面上的Spinner控件,用于切换模型
private int current_model = 0;
private Spinner spinnerCPUGPU; // Spinner控件,用于切换CPU/GPU
private int current_cpugpu = 0;

private SurfaceView cameraView; // SurfaceView 控件,用于显示相机画面

/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 根据Xml初始化界面布局(R是自动生成的资源类,控制所有的Resources)
setContentView(R.layout.main);
// 设置保持屏幕常亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

// 获取布局中的相机画面预览控件 (SurfaceView)
cameraView = (SurfaceView) findViewById(R.id.cameraview);
// 设置相机传输过来的数据格式为 RGBA_8888 (具体的可以根据手机的不同而更改,一般是这个)
cameraView.getHolder().setFormat(PixelFormat.RGBA_8888);
// TODO: 为 SurfaceView 设置回调接口
cameraView.getHolder().addCallback(this);

// 获取切换前置后置摄像头的Button控件
Button buttonSwitchCamera = (Button) findViewById(R.id.buttonSwitchCamera);
// 为点击摄像头的按钮写一个槽函数(事件),实现切换摄像头功能
buttonSwitchCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 0->1, 1->0
int new_facing = 1 - facing;
yolov8ncnn.closeCamera();
yolov8ncnn.openCamera(new_facing);
facing = new_facing;
}
});

// 获取并设置模型选择 Spinner 的监听器
spinnerModel = (Spinner) findViewById(R.id.spinnerModel);
spinnerModel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
if (position != current_model) {
current_model = position;
// 重新加载(新的)模型
reload();
}
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});

// 获取并设置 CPU/GPU 选择 Spinner 的监听器
spinnerCPUGPU = (Spinner) findViewById(R.id.spinnerCPUGPU);
spinnerCPUGPU.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
if (position != current_cpugpu) {
current_cpugpu = position;
reload(); // 同样的,切换了设备,模型也需要重载
}
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
// 第一次启动,用默认参数加载模型
reload();
}

private void reload() {
// 加载模型
boolean ret_init = yolov8ncnn.loadModel(getAssets(), current_model, current_cpugpu);
if (!ret_init) {
Log.e("MainActivity", "yolov8ncnn loadModel failed");
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// 当 SurfaceView 的大小发生变化时调用此方法,设置输出的 Surface 为 Camera 的预览界面
yolov8ncnn.setOutputWindow(holder.getSurface());
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}

// note: 从后台重新回到该程序时应该做的
@Override
public void onResume() {
super.onResume();

if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
}

yolov8ncnn.openCamera(facing);
}

// note: 程序到后台时,关闭摄像头
@Override
public void onPause() {
super.onPause();

yolov8ncnn.closeCamera();
}
}
23 changes: 23 additions & 0 deletions android-demo/app/src/main/java/com/gyq/yolov8/Yolov8Ncnn.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* note: 这里只是声明接口,用于与 C++ 层通过 JNI (Java Native Interface) 进行交互
*/
package com.gyq.yolov8;

import android.content.res.AssetManager;
import android.view.Surface;

public class Yolov8Ncnn {
// mgr 是 AssetManager 用来访问应用的资源文件, modelid 是模型的 ID,cpugpu 指定使用 CPU 还是 GPU
public native boolean loadModel(AssetManager mgr, int modelid, int cpugpu);
// facing 指定打开摄像头的方向
public native boolean openCamera(int facing);
// 关闭摄像头
public native boolean closeCamera();
// 数 surface 是输出图像的显示界面,是一个 SurfaceView 控件
public native boolean setOutputWindow(Surface surface);

// 通过JNI,这些声明成 public native 的方法可以用C++方法实现
static {
System.loadLibrary("yolov8ncnn");
}
}
23 changes: 23 additions & 0 deletions android-demo/app/src/main/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.10)
project(yolov8ncnn)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Werror,-Wformat-security")

include_directories(ocsort/include)
include_directories(eigen)
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.6.0-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)

set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20230223-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)


add_library(yolov8ncnn SHARED yolov8ncnn.cpp yolo.cpp ndkcamera.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/lapjv.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/KalmanFilter.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/KalmanBoxTracker.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/association.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/OCsort.cpp
${CMAKE_SOURCE_DIR}/ocsort/src/Utilities.cpp
)
target_link_libraries(yolov8ncnn ncnn ${OpenCV_LIBS} camera2ndk mediandk)
9 changes: 9 additions & 0 deletions android-demo/app/src/main/jni/Object.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once
#include <opencv2/core/core.hpp>
struct Object
{
// Generally it is the coordinates of the top left corner + width and height
cv::Rect_<float> rect;
int label;
float prob;
};
Loading

0 comments on commit 45d7774

Please sign in to comment.