diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/load_image_error.png b/app/src/main/res/mipmap-hdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/load_image_error.png Binary files differ diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/load_image_error.png b/app/src/main/res/mipmap-hdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-mdpi/load_image_error.png b/app/src/main/res/mipmap-mdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/load_image_error.png Binary files differ diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/load_image_error.png b/app/src/main/res/mipmap-hdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-mdpi/load_image_error.png b/app/src/main/res/mipmap-mdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/load_image_error.png b/app/src/main/res/mipmap-xhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xhdpi/load_image_error.png Binary files differ diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/load_image_error.png b/app/src/main/res/mipmap-hdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-mdpi/load_image_error.png b/app/src/main/res/mipmap-mdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/load_image_error.png b/app/src/main/res/mipmap-xhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xhdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xxhdpi/load_image_error.png b/app/src/main/res/mipmap-xxhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/load_image_error.png Binary files differ diff --git a/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt new file mode 100644 index 0000000..73c483b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/INativeCallback.kt @@ -0,0 +1,18 @@ +package com.casic.br.ar.app.external + +interface INativeCallback { + /** + * 分类 + */ + fun onClassify(possibles: FloatArray) + + /** + * 分割 + */ + fun onPartition(output: ArrayList) + + /** + * 检测 + */ + fun onDetect(output: YoloResult) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java new file mode 100644 index 0000000..db9fbb0 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloResult.java @@ -0,0 +1,31 @@ +package com.casic.br.ar.app.external; + +public class YoloResult { + private int type; + private float[] position; + private float prob; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public float[] getPosition() { + return position; + } + + public void setPosition(float[] position) { + this.position = position; + } + + public float getProb() { + return prob; + } + + public void setProb(float prob) { + this.prob = prob; + } +} diff --git a/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt new file mode 100644 index 0000000..f0277b7 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/YoloStateConst.kt @@ -0,0 +1,19 @@ +package com.casic.br.ar.app.external + +@Retention(AnnotationRetention.SOURCE) +annotation class YoloStateConst { + companion object { + /** + * Yolo当前状态 + *
------------------------------
+ * 0 - 分类 + * 1 - 分割 + * 2 - 检测 + * 3 - 绘制 + * */ + const val CLASSIFY = 0 + const val PARTITION = 1 + const val DETECT = 2 + const val DRAW = 3 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt new file mode 100644 index 0000000..4f94a1b --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/external/Yolov8ncnn.kt @@ -0,0 +1,35 @@ +package com.casic.br.ar.app.external + +import android.content.res.AssetManager +import android.view.Surface + +class Yolov8ncnn { + + companion object { + init { + System.loadLibrary("yolov8ncnn") + } + } + + /** + * @param mgr 手机内存资源管理器 + * @param model_id 模型ID + * @param processor 是否使用GPU 1-是,0-否 + * */ + external fun loadModel(mgr: AssetManager, model_id: Int, processor: Int): Boolean + + /** + * @param facing 相机 0-前置镜头,1-后置镜头 + * */ + external fun openCamera(facing: Int): Boolean + + external fun closeCamera(): Boolean + + external fun setOutputWindow( + surface: Surface, input: YoloResult, nativeObjAddr: Long, callBack: INativeCallback + ): Boolean + + external fun updateYoloState(@YoloStateConst yoloState: Int): Boolean + + external fun getYoloCurrentState(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt new file mode 100644 index 0000000..333ab62 --- /dev/null +++ b/app/src/main/java/com/casic/br/ar/app/widgets/YoloTargetDetectView.kt @@ -0,0 +1,81 @@ +package com.casic.br.ar.app.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import com.casic.br.ar.app.external.YoloResult +import com.casic.br.ar.app.utils.LocaleConstant +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.sp2px + +class YoloTargetDetectView constructor(context: Context, attrs: AttributeSet) : + View(context, attrs) { + + private val kTag = "DetectView" + private val textPaint by lazy { TextPaint() } + private val backgroundPaint by lazy { Paint() } + private val borderPaint by lazy { Paint() } + private val rect by lazy { Rect() } + private var result: YoloResult? = null + + init { + textPaint.color = Color.WHITE + textPaint.isAntiAlias = true + textPaint.textAlign = Paint.Align.CENTER + textPaint.textSize = 14f.sp2px(context) + + backgroundPaint.color = Color.BLUE + backgroundPaint.style = Paint.Style.FILL + backgroundPaint.isAntiAlias = true + + borderPaint.color = Color.BLUE + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = 2f.dp2px(context) //设置线宽 + borderPaint.isAntiAlias = true + } + + fun updateTargetPosition(result: YoloResult) { + this.result = result + postInvalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + result?.apply { + val prob = String.format("%.2f", this.prob * 100) + val label = "${LocaleConstant.CLASS_NAMES_ARRAY[this.type]} ${prob}%" + val textLength = textPaint.measureText(label) + + //文字背景 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[0].dp2px(context) + textLength).toInt() + 10, + this.position[1].dp2px(context).toInt() - 50 + ) + canvas.drawRect(rect, backgroundPaint) + + //画文字。数值是文字左右边距,可酌情调整 + canvas.drawText( + label, + this.position[0].dp2px(context) + (textLength + 10) / 2, + this.position[1].dp2px(context) - 10, + textPaint + ) + + //画框 + rect.set( + (this.position[0].dp2px(context)).toInt(), + (this.position[1].dp2px(context)).toInt(), + (this.position[2] + this.position[0]).dp2px(context).toInt(), + (this.position[3] + this.position[1]).dp2px(context).toInt() + ) + canvas.drawRect(rect, borderPaint) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_readonly_gv.xml b/app/src/main/res/layout/item_readonly_gv.xml new file mode 100644 index 0000000..346b241 --- /dev/null +++ b/app/src/main/res/layout/item_readonly_gv.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/load_image_error.png b/app/src/main/res/mipmap-hdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-mdpi/load_image_error.png b/app/src/main/res/mipmap-mdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/load_image_error.png b/app/src/main/res/mipmap-xhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xhdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xxhdpi/load_image_error.png b/app/src/main/res/mipmap-xxhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/load_image_error.png Binary files differ diff --git a/app/src/main/res/mipmap-xxxhdpi/load_image_error.png b/app/src/main/res/mipmap-xxxhdpi/load_image_error.png new file mode 100644 index 0000000..357cbde --- /dev/null +++ b/app/src/main/res/mipmap-xxxhdpi/load_image_error.png Binary files differ