专栏首页贾志刚-OpenCV学堂OpenCV4.4 + YOLOv4 真的可以运行了…..

OpenCV4.4 + YOLOv4 真的可以运行了…..

微信公众号:OpenCV学堂

前一阵子YOLOv4发布了,后面就是YOLOv5,估计再过几天就要YOLOv10086了,这个时代技术进步太魔幻,改几个参数就可以继续升级版本。2020.718 OpenCV4.4发布了,支持YOLOv4推理,于是我立刻测试了一波。

模型下载

YOLOv4的相关模型合集在这里

https://github.com/AlexeyAB/darknet/wiki/YOLOv4-model-zoo

我使用的是基于COCO预训练模型:

YOLOv4-Leaky

OpenCV4.4 DNN

OpenCV4.4 支持YOLOv4,这个是它的官方release里面说的,其实我早就发现了YOLOv4可以通过OpenCV4.2直接跑,怎么OpenCV4.4才官宣。也许不发布新版本不好官宣,只有发布了新版本才可以顺便说一下。此外OpenCV4.4 DNN还有很多新添加的演示程序,支持了深度学习的光流、支持tensorflow object detection API的EfficientDet对象检测模型,但是前提是tensorflow2.x才可以。多了一个tf_text_graph_efficientdet.py文件,用来生成对应的pbtxt文件。

OpenCV4.4 DNN + YOLOv4对象检测演示

跟YOLOv3一样,YOLOv4也有三个输出层,完成推理之后,需要在进一步通过NMS实现对重叠框的去除,什么是NMS(非最大抑制),看下图就懂啦:

然后说一下模型输入格式与输出格式

输入:NCHW=1x3x416x416 输出:NXC 其中N表示多少个对象,C的前四个数矩形框的[center_x, center_y, width, height],从第五个数值开始分别是每个类别的得分,求的最大得分,如果高于阈值0.5,则认为检测到了对象,每个score对应的index即是COCO类别文本。

根据上面的描述,对一个视频文件实现YOLOv4的对象检测代码如下:

Net net = readNetFromDarknet(yolov4_config, yolov4_model);
net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
net.setPreferableTarget(DNN_TARGET_CPU);
std::vector<String> outNames = net.getUnconnectedOutLayersNames();
for (int i = 0; i < outNames.size(); i++) {
    printf("output layer name : %s\n", outNames[i].c_str());
}

vector<string> classNamesVec;
ifstream classNamesFile("D:/projects/opencv_tutorial/data/models/object_detection_classes_yolov3.txt");
if (classNamesFile.is_open())
{
    string className = "";
    while (std::getline(classNamesFile, className))
        classNamesVec.push_back(className);
}

VideoCapture capture;
capture.open("D:/images/video/f35_02.mp4");
Mat frame;
// 加载图像 
while (true) {
    int64 start = getTickCount();
    capture.read(frame);
    Mat inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false);
    net.setInput(inputBlob);

    // 检测
    std::vector<Mat> outs;
    net.forward(outs, outNames);

    vector<Rect> boxes;
    vector<int> classIds;
    vector<float> confidences;
    for (size_t i = 0; i<outs.size(); ++i)
    {
        // detected objects and C is a number of classes + 4 where the first 4
        float* data = (float*)outs[i].data;
        for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
        {
            Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
            Point classIdPoint;
            double confidence;
            minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
            if (confidence > 0.5)
            {
                int centerX = (int)(data[0] * frame.cols);
                int centerY = (int)(data[1] * frame.rows);
                int width = (int)(data[2] * frame.cols);
                int height = (int)(data[3] * frame.rows);
                int left = centerX - width / 2;
                int top = centerY - height / 2;

                classIds.push_back(classIdPoint.x);
                confidences.push_back((float)confidence);
                boxes.push_back(Rect(left, top, width, height));
            }
        }
    }

    vector<int> indices;
    NMSBoxes(boxes, confidences, 0.5, 0.2, indices);
    for (size_t i = 0; i < indices.size(); ++i)
    {
        int idx = indices[i];
        Rect box = boxes[idx];
        String className = classNamesVec[classIds[idx]];
        putText(frame, className.c_str(), box.tl(), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2, 8);
        rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);
    }
    float fps = getTickFrequency() / (getTickCount() - start);
    float time = (getTickCount() - start) / getTickFrequency();
    ostringstream ss;
    ss << "FPS : "<< fps <<" detection time: " << time*1000 << " ms";
    putText(frame, ss.str(), Point(20, 20), 0, 0.5, Scalar(0, 0, 255));
    imshow("YOLOv4-Detections", frame);
    char c = waitKey(1);
    if (c == 27) {
        break;
    }
}
waitKey(0);
return;

代码运行结果如下:

我只能说速度有点感人,我有点怕啦,当然我是在i7CPU上运行的。

本文分享自微信公众号 - OpenCV学堂(CVSCHOOL),作者:gloomyfish

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OpenCV中积分图介绍与应用

    OpenCV中积分图函数与应用 一:图像积分图概念 积分图像是Crow在1984年首次提出,是为了在多尺度透视投影中提高渲染速度。随后这种技术被应用到基于NC...

    OpenCV学堂
  • App基于手机壳颜色换肤?先尝试一下用 KMeans 来提取图像中的主色

    上周,某公司的产品经理提了一个需求:根据用户手机壳颜色来改变 App 主题颜色。可能是由于这天马行空的需求激怒了程序员,导致程序员和产品经理打了起来,最后双双被...

    OpenCV学堂
  • OpenCV轮廓层次分析实现欧拉数计算

    二值图像分析中欧拉数重要的拓扑特征之一,在图像分析与几何对象识别中有着十分重要的作用,二值图像的欧拉数计算公式表示如下: E = N – H 其中 E表示计算...

    OpenCV学堂
  • 2017年海淀区信息学竞赛小学组详细答案

    海天一树
  • BZOJ1485: [HNOI2009]有趣的数列(Catalan数,质因数分解求组合数)

    考虑到每个数的最小的质因数$ \geqslant 2$,因此极限复杂度为$O(n log n)$

    attack
  • P3717 [AHOI2017初中组]cover

    题目背景 以下为不影响题意的简化版题目。 题目描述 一个n*n的网格图上有m个探测器,每个探测器有个探测半径r,问这n*n个点中有多少个点能被探测到。 输入输出...

    attack
  • 10:矩阵转置

    10:矩阵转置 总时间限制: 1000ms 内存限制: 65536kB描述 输入一个n行m列的矩阵A,输出它的转置AT。 输入第一行包含两个整数n和m,...

    attack
  • AtCoder Beginner Contest 154

    思路:这个题不是很难,但是我一上去就想要用map,然后就很悲催,map里面人家按照键值给你排序,所以输出的时候会有错!

    用户7727433
  • P1028 数的计算

    思路:通过演算,我们很容易就能得到, f[1] = 1; f[2] = f[1] +1; f[3] = f[1] + 1; f[4] = f[2] + ...

    用户7727433
  • 【PAT乙级】判断题

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    喜欢ctrl的cxk

扫码关注云+社区

领取腾讯云代金券