Android使用OpenCV加载darknet的YOLO目标检测

介绍:

实现了在android上使用opencv运行yolo。

平台:

android studio:3.5
android sdk:28
gradle plugin:3.5.0
gradle version:5.4.1
opencv android sdk:3.4.5
yolo:yolov2-tiny
运行于:android9
语言:java

创建项目并配置opencv:

需要注意的是:
OpenCV在3.3.1版本中开始支持Darknet的YOLO2,在3.4.2开始支持YOLO3。所以一定要选择好对应的版本。

OpenCV可以用c++的接口和java的接口。这里我们简单一些,直接使用java。
参考:
https://blog.csdn.net/babytiger/article/details/86614572

作者说:“如果没出来module name就说明你路径不对,但我尝试opencv4.0.1时就没有,退而求其次安了3.4.5”

在这里插入图片描述

其实,这是因为opencv工程的gradle是以apply plugin: 'com.android.application'配置的。
需要apply plugin: 'com.android.library'才能以module导入。
opencv的gradle
在这里插入图片描述

准备yolo模型:

yolo模型、参数等是在这里下载的:
https://github.com/AlexeyAB/darknet

为了方便,直接在手机下建了个文件夹yolo3,放入了模型、参数、和类型、以及测试图片。
在这里插入图片描述

读取模型记得要在AndroidManifest.xml里添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

申请权限的方法:

boolean isGrantExternalRW(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        activity.requestPermissions(new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, 1);
        return false;
    }
    return true;
}

之后在onCreate里调用。

加载yolo模型:

这里定义了一个类,具体方法参考了其他玩家的代码,但是找不到链接了。谢谢他们。再次感谢。


public class Yolo3 {
    private List<String> classNamesVec;
    private Net net;
    private String filePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/yolo3/";
    void init(Context activity){
        try {   //读取names
            File file = new File(filePath+"coco.names");
            InputStream instream = new FileInputStream(file);
            InputStreamReader inputreader = new InputStreamReader(instream);
            BufferedReader buffreader = new BufferedReader(inputreader);
            String line;
            while ((line = buffreader.readLine()) != null) {
                classNamesVec.add(line);
            }
            instream.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
        String cfgPath = filePath+"yolov2-tiny.cfg";
        String weightsPath = filePath+"yolov2-tiny.weights";
        net = Dnn.readNetFromDarknet(cfgPath,weightsPath);
        if ( net.empty() ) {
            Log.e("error","Reading Net error");
        }
    }
Bitmap test(){
    String image_file = "dog.jpg";
    Mat im = Imgcodecs.imread(filePath + image_file, Imgcodecs.IMREAD_COLOR);
//    Imgproc.cvtColor(im, im, Imgproc.COLOR_BGR2RGB);	//转换通道
    Log.e("path:",filePath + image_file);
    Mat out = draw(detection(im),im);
    Bitmap bmp = Bitmap.createBitmap(out.cols(),out.rows(),Bitmap.Config.ARGB_8888);
    org.opencv.android.Utils.matToBitmap(out,bmp);
    return bmp;
}
Mat detection(Mat im){
        if( im.empty() ) {
            Log.e("error","Reading Image error");
        }
        Mat frame = new Mat();
        Size sz1 = new Size(im.cols(),im.rows());
        Imgproc.resize(im, frame, sz1);
        Mat resized = new Mat();
        Size sz = new Size(416,416);
        Imgproc.resize(im, resized, sz);
        float scale = 1.0F / 255.0F;
        Mat inputBlob = Dnn.blobFromImage(im, scale, sz, new Scalar(0), false, false);
        net.setInput(inputBlob, "data");
        Mat detectionMat = net.forward("detection_out");
        return detectionMat;
    }
    Mat draw(Mat detectionMat,Mat frame){
        if( !detectionMat.empty() ) {
            for (int i = 0; i < detectionMat.rows(); i++) {
                int probability_index = 5;
                int size = (int) (detectionMat.cols() * detectionMat.channels());
                float[] data = new float[size];
                detectionMat.get(i, 0, data);
                float confidence = -1;
                int objectClass = -1;
                for (int j = 0; j < detectionMat.cols(); j++) {
                    if (j >= probability_index && confidence < data[j]) {
                        confidence = data[j];
                        objectClass = j - probability_index;
                    }
                }
                if (confidence > 0.3) {
//                System.out.println("Result Object: "+i);
//                for (int j=0; j < detectionMat.cols();j++)
//                    System.out.print(" "+j+":"+ data[j]);
//                System.out.println("");
                    float x = data[0];
                    float y = data[1];
                    float width = data[2];
                    float height = data[3];
                    float xLeftBottom = (x - width / 2) * frame.cols();
                    float yLeftBottom = (y - height / 2) * frame.rows();
                    float xRightTop = (x + width / 2) * frame.cols();
                    float yRightTop = (y + height / 2) * frame.rows();
//                System.out.println("Class: "+ names[objectClass]);
//                System.out.println("Confidence: "+confidence);
//                System.out.println("ROI: "+xLeftBottom+" "+yLeftBottom+" "+xRightTop+" "+yRightTop+"\n");
                    Imgproc.rectangle(frame, new Point(xLeftBottom, yLeftBottom),
                            new Point(xRightTop, yRightTop), new Scalar(0, 255, 0), 3);
                }
            }
        }
        return frame;
    }
}

测试yolo3

在视图里随便建了个button,在clickListener里调用test方法

yolo3.init(getApplicationContext());
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    	yolo3.init(getApplicationContext());
        ImageView imageView = findViewById(R.id.imageView);
        imageView.setImageBitmap(yolo3.test());
    }
});

记得必须要加载完OpenCV以后才能调用yolo3.init(getApplicationContext());加载模型。
加载OpenCV:OpenCVLoader.initDebug();
在这里插入图片描述这么奇怪的颜色是因为OpenCV的通道顺序是BGR,所以要记得转换一下通道顺序。

Imgproc.cvtColor(im, im, Imgproc.COLOR_BGR2RGB);

这样对Mat调整后再显示就正常啦。
在这里插入图片描述

后记

完工啦

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值