C++应用中调用YOLOv3(darknet)进行目标检测

2023-05-16

YOLOv3论文:https://pjreddie.com/media/files/papers/YOLOv3.pdf

官网和代码:https://pjreddie.com/darknet/

yolo属于one-stage(检测一步到位),兼顾准确率和速度,特别是最近的v3版本提高了小目标的检测率,是移动端目标检测的热门算法。关于YOLO原理的介绍网上有很多资料请自行百度,本文主要介绍如何在自己的cpp中调用yolov3进行目标检测。

yolo采用自定义的image格式进行图像读取和处理,而一般我们工程中使用较多的是OpenCV或者指向图像数据的指针,因此此处先对图像转换和缩放操作进行修改,代码如下:

#ifndef IMPROCESS_H
#define IMPROCESS_H

#include<opencv2/opencv.hpp>

void imgConvert(const cv::Mat& img, float* dst);

void imgResize(float* src, float* dst,int srcWidth,int srcHeight,int dstWidth,int dstHeight);

void resizeInner(float *src, float* dst,int srcWidth,int srcHeight,int dstWidth,int dstHeight);

#endif // IMPROCESS_H
#include<improcess.h>

void imgConvert(const cv::Mat& img, float* dst){
    uchar *data = img.data;
    int h = img.rows;
    int w = img.cols;
    int c = img.channels();

    for(int k= 0; k < c; ++k){
        for(int i = 0; i < h; ++i){
            for(int j = 0; j < w; ++j){
                dst[k*w*h+i*w+j] = data[(i*w + j)*c + k]/255.;
            }
        }
    }
}

void imgResize(float *src, float* dst,int srcWidth,int srcHeight,int dstWidth,int dstHeight){
    int new_w = srcWidth;
    int new_h = srcHeight;
    if (((float)dstWidth/srcWidth) < ((float)dstHeight/srcHeight)) {
        new_w = dstWidth;
        new_h = (srcHeight * dstWidth)/srcWidth;
    } else {
        new_h = dstHeight;
        new_w = (srcWidth * dstHeight)/srcHeight;
    }

    float* ImgReInner;
    size_t sizeInner=new_w*new_h*3*sizeof(float);
    ImgReInner=(float*)malloc(sizeInner);
    resizeInner(src,ImgReInner,srcWidth,srcHeight,new_w,new_h);

    for(int i=0;i<dstWidth*dstHeight*3;i++){
        dst[i]=0.5;
    }

    for(int k = 0; k < 3; ++k){
        for(int y = 0; y < new_h; ++y){
            for(int x = 0; x < new_w; ++x){
                float val = ImgReInner[k*new_w*new_h+y*new_w+x];
                dst[k*dstHeight*dstWidth + ((dstHeight-new_h)/2+y)*dstWidth + (dstWidth-new_w)/2+x]=val;
            }
        }
    }
    free(ImgReInner);
}

void resizeInner(float *src, float* dst,int srcWidth,int srcHeight,int dstWidth,int dstHeight){
    float* part;
    size_t sizePa=dstWidth*srcHeight*3*sizeof(float);
    part=(float*)malloc(sizePa);

    float w_scale = (float)(srcWidth - 1) / (dstWidth - 1);
    float h_scale = (float)(srcHeight - 1) / (dstHeight - 1);

    for(int k = 0; k < 3; ++k){
        for(int r = 0; r < srcHeight; ++r){
            for(int c = 0; c < dstWidth; ++c){
                float val = 0;
                if(c == dstWidth-1 || srcWidth == 1){
                    val=src[k*srcWidth*srcHeight+r*srcWidth+srcWidth-1];
                } else {
                    float sx = c*w_scale;
                    int ix = (int) sx;
                    float dx = sx - ix;
                    val=(1 - dx) * src[k*srcWidth*srcHeight+r*srcWidth+ix] + dx * src[k*srcWidth*srcHeight+r*srcWidth+ix+1];
                }
                part[k*srcHeight*dstWidth + r*dstWidth + c]=val;
            }
        }
    }

    for(int k = 0; k < 3; ++k){
        for(int r = 0; r < dstHeight; ++r){
            float sy = r*h_scale;
            int iy = (int) sy;
            float dy = sy - iy;
            for(int c = 0; c < dstWidth; ++c){
                float val = (1-dy) * part[k*dstWidth*srcHeight+iy*dstWidth+c];
                dst[k*dstWidth*dstHeight + r*dstWidth + c]=val;
            }
            if(r == dstHeight-1 || srcHeight == 1)
                continue;
            for(int c = 0; c < dstWidth; ++c){
                float val = dy * part[k*dstWidth*srcHeight+(iy+1)*dstWidth+c];
                dst[k*dstWidth*dstHeight + r*dstWidth + c]+=val;
            }
        }
    }
    free(part);
}

其中,imgConvert函数将OpenCV的图像由RGBRGBRGB...转化为yolo的RRRGGGBBB...格式(由代码可知,yolo输入图像的像素取值范围为0~1)。imgResize函数将图像缩放到cfg指定的网络输入的大小。代码修改自yolo的源码,将其image格式改为我们需要的指针形式。

接下来是调用darknet的代码,为了让代码跑通,我们首先用OpenCV读取视频,然后将OpenCV的图像转为指针指向的数据格式(如果想直接采用OpenCV可自行修改)。代码如下:

#include<iostream>
#include<opencv2/opencv.hpp>
#include<darknet.h>
#include<improcess.h>

using namespace std;
using namespace cv;

float colors[6][3] = { {1,0,1}, {0,0,1},{0,1,1},{0,1,0},{1,1,0},{1,0,0} };

float get_color(int c, int x, int max){
    float ratio = ((float)x/max)*5;
    int i = floor(ratio);
    int j = ceil(ratio);
    ratio -= i;
    float r = (1-ratio) * colors[i][c] + ratio*colors[j][c];
    return r;
}


int main()
{
    string cfgfile = "/home/chnn/darknet/cfg/yolov3.cfg";//读取模型文件,请自行修改相应路径
    string weightfile = "/home/chnn/darknet/yolov3.weights";
    float thresh=0.5;//参数设置
    float nms=0.35;
    int classes=80;

    network *net=load_network((char*)cfgfile.c_str(),(char*)weightfile.c_str(),0);//加载网络模型
    set_batch_network(net, 1);
    VideoCapture capture("/home/chnn/video/videoCapture6.mp4");//读取视频,请自行修改相应路径
    Mat frame;
    Mat rgbImg;

    vector<string> classNamesVec;
    ifstream classNamesFile("/home/chnn/darknet/data/coco.names");//标签文件coco有80类

    if (classNamesFile.is_open()){
        string className = "";
        while (getline(classNamesFile, className))
            classNamesVec.push_back(className);
    }

    bool stop=false;
    while(!stop){
        if (!capture.read(frame)){
            printf("fail to read.\n");
            return 0;
        }
        cvtColor(frame, rgbImg, cv::COLOR_BGR2RGB);

        float* srcImg;
        size_t srcSize=rgbImg.rows*rgbImg.cols*3*sizeof(float);
        srcImg=(float*)malloc(srcSize);

        imgConvert(rgbImg,srcImg);//将图像转为yolo形式

        float* resizeImg;
        size_t resizeSize=net->w*net->h*3*sizeof(float);
        resizeImg=(float*)malloc(resizeSize);
        imgResize(srcImg,resizeImg,frame.cols,frame.rows,net->w,net->h);//缩放图像

        network_predict(net,resizeImg);//网络推理
        int nboxes=0;
        detection *dets=get_network_boxes(net,rgbImg.cols,rgbImg.rows,thresh,0.5,0,1,&nboxes);

        if(nms){
            do_nms_sort(dets,nboxes,classes,nms);
        }

        vector<cv::Rect>boxes;
        boxes.clear();
        vector<int>classNames;

        for (int i = 0; i < nboxes; i++){
            bool flag=0;
            int className;
            for(int j=0;j<classes;j++){
                if(dets[i].prob[j]>thresh){
                    if(!flag){
                        flag=1;
                        className=j;
                    }
                }
            }
            if(flag){
                int left = (dets[i].bbox.x - dets[i].bbox.w / 2.)*frame.cols;
                int right = (dets[i].bbox.x + dets[i].bbox.w / 2.)*frame.cols;
                int top = (dets[i].bbox.y - dets[i].bbox.h / 2.)*frame.rows;
                int bot = (dets[i].bbox.y + dets[i].bbox.h / 2.)*frame.rows;

                if (left < 0)
                    left = 0;
                if (right > frame.cols - 1)
                    right = frame.cols - 1;
                if (top < 0)
                    top = 0;
                if (bot > frame.rows - 1)
                    bot = frame.rows - 1;

                Rect box(left, top, fabs(left - right), fabs(top - bot));
                boxes.push_back(box);
                classNames.push_back(className);
            }
        }
        free_detections(dets, nboxes);

        for(int i=0;i<boxes.size();i++){
            int offset = classNames[i]*123457 % 80;
            float red = 255*get_color(2,offset,80);
            float green = 255*get_color(1,offset,80);
            float blue = 255*get_color(0,offset,80);

            rectangle(frame,boxes[i],Scalar(blue,green,red),2);

            String label = String(classNamesVec[classNames[i]]);
            int baseLine = 0;
            Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
            putText(frame, label, Point(boxes[i].x, boxes[i].y + labelSize.height),
                    FONT_HERSHEY_SIMPLEX, 1, Scalar(red, blue, green),2);
        }
        imshow("video",frame);

        int c=waitKey(30);
              if((char)c==27)
                  break;
              else if(c>=0)
                  waitKey(0);

        free(srcImg);
        free(resizeImg);
    }
    free_network(net);
    capture.release();
    return 1;
}

链接上darknet的动态库并让代码运行,最后得出来的结果应该是这样的:

请忽略人体姿态信息。。。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++应用中调用YOLOv3(darknet)进行目标检测 的相关文章

随机推荐

  • PROCESS_YIELD()宏和C语言的switch语句< contiki学习笔记之七>

    写在前面 xff1a 按照main 函数的代码一行一行的分析 xff0c 该是看到了 etimer process 这个位置 但是etimer process实现里的一个宏 PROCESS YIELD 引出了很多故事 xff0c 于是单独把
  • 用c语言指针实现vector,C使用指针将对象添加到Vector中

    我有一个向量添加包含 SDL Surface 指针作为数据成员的对象 xff0c 这意味着我必须使用复制构造函数来实现指针的深层复制 该对象释放析构函数中的表面 指针 xff0c 这就是问题发生的地方 当对象被添加到向量中时 通过按下按钮
  • 【Http认证方式】——Basic认证

    访问请求 xff1a http 192 168 2 113 8080 geoserver rest workspaces时 xff0c 浏览器弹出窗口需要输入用户名和密码 xff0c 并且 xff0c 如果不输入或者输入错误 xff0c 浏
  • c++ http请求

    平常我们要访问某个URL一般都是通过浏览器进行 xff1a 提交一个URL请求后 xff0c 浏览器将请求发向目标服务器或者代理服务器 xff0c 目标服务器或者代理服务器返回我们所需要的数据 xff0c 浏览器接收到这些数据后保存成文件并
  • libcurl实现http登录功能

    用Fiddler Web Debugger捕捉http数据包 xff1a 观察看看 xff0c POST请求的地址为http passport cnblogs com login aspx ReturnUrl 61 http 3a 2f 2
  • 服务器机柜和网络机柜的区别

    原文转载自 http www fwqtg net 服务器机柜 xff0c 用来组合安装面板 插件 插箱 电子元件 器件和机械零件与部件 xff0c 使其构成一个整体的安装箱 服务器机柜由框架和盖板 xff08 门 xff09 组成 xff0
  • Eclipse+Maven创建webapp项目<一>

    Eclipse 43 Maven创建webapp项目 lt 一 gt 1 开启eclipse xff0c 右键new other xff0c 如下图找到maven project 2 选择maven project xff0c 显示创建ma
  • java日期格式(年月日时分秒毫秒)

    package test remote tools combine import java text SimpleDateFormat import java util Calendar import java util Date impo
  • 游戏中的帧同步要求的计算一致性——定点数(Fixed Point)

    最近做了一款帧同步游戏 xff0c 其寻路算法采用了RVO算法 但是由于是移动端的游戏 需要在不同的设备上运行 xff0c 其所有运算必须符合一致性 即所有客户端运算出来的结果必须一致 但是由于浮点数的特性 xff0c 具有误差 xff0c
  • 敏捷测试驱动模式-项目质量保障体系

    结合敏捷项目管理 xff0c 测试驱动模式 xff0c 让测试跑起来 我给这套体系的定义就是 保障质量的同时保证项目进度 xff0c 四个节点及时反馈及时沟通 xff0c 有效的让产品 研发和测试都动起来 xff0c 避免任意一方的停滞 质
  • angularjs自定义指令函数传参

    问题描述 在编写导入指令的时候 xff0c 需要将函数绑定到指令中 xff0c 并传入一个参数 初步实现 首先指令的js文件如下 xff0c 基本的绑定参数和绑定函数 xff0c 没有什么说的 xff1a angular module 39
  • 浅谈JSONObject解析JSON数据

    个人博客同步文章 https mr houzi com 2018 06 根据一段天气API来说一下JSONObject如何解析json数据 xff0c 尽管现在在开发中使用Gson等 xff0c 对于像我这样初次使用Java做开发的小白 x
  • 能ping通,但是不能wget或curl

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 当出现http接口请求超时时 xff0c 可以从以下几个方面排查问题 xff1a 检查接口服务本身是否正常 xff1b 检查接口所在服务器的防火墙是否开启 xff0c 尝试
  • R语言选择特定的行,对某一列排序

    R语言的数据框跟MySQL 中的表很像 根据某一列的特定值选择相应的行 d是个数据框 xff0c 有一列的名字是name d d name 61 61 34 95 34 这样就选中了 name为 95 的所有行 m 是个数据框 xff0c
  • excel表格公式无效、不生效的解决方案及常见问题、常用函数

    1 表格公式无效 不生效 使用公式时碰到了一个问题 xff0c 那就是公式明明已经编辑好了 xff0c 但是在单元格里不生效 xff0c 直接把公式显示出来了 xff0c 网上资料说有4种原因 xff0c 但是我4种都不是 xff0c 是第
  • JVM_栈详解一

    1 Java虚拟机栈 2 栈的存储单位 栈中存储什么 xff1f 每个线程都有自己的栈 xff0c 栈中的数据都是以栈帧 xff08 Stack Frame xff09 的格式存在 在这个线程上正在执行的每个方法都各自对应一个栈帧 xff0
  • EntLib 3.1学习笔记(6) : Security Application Block

    http www microsoft com china MSDN library enterprisedevelopment softwaredev dnpag2entlib mspx mfr 61 true http msdn2 mic
  • Delphi文件操作所涉及的一些函数 附例子

    判断文件是否存在 FileExists 判断文件夹是否存在 DirectoryExists 删除文件 DeleteFile Windows DeleteFile 删除文件夹 RemoveDir RemoveDirectory 获取当前文件夹
  • 排序算法

    include lt iostream gt include lt cstdlib gt include lt cstdio gt include lt time h gt using namespace std 插入排序 void Ins
  • C++应用中调用YOLOv3(darknet)进行目标检测

    YOLOv3论文 xff1a https pjreddie com media files papers YOLOv3 pdf 官网和代码 xff1a https pjreddie com darknet yolo属于one stage x