yolov3模型C++API程序样例

yolov3自带了一个视频测试的demo,是c语言写的,本文根据yolov3的makefile结合自身需要,编写一个GPU版本的darknet.so库调用程序。将库的调用和应用程序分开来编译,具体的程序如下所示:

main.cpp

#include 
#include 
#include 
#include 
#include "opencv2/opencv.hpp" 
#include "highgui.h"
#include "detect_obj.h"

void video_test(char * _video) ; 



int main(int argc,char **argv)
{
    video_test(argv[1]);
    return 0 ;    
}
//use this function to process video for detecting object
void video_test(char * _video)
{

    detect_obj * detect_yolo = new detect_obj();
    if(!detect_yolo->load_net("/home/wq/darknet/cfg/coco.data", \
      "/home/wq/darknet/cfg/yolov3.cfg", "/home/wq/darknet/yolov3.weights",\
      "/home/wq/darknet/data/names.list") ) 
        return ;

    CvCapture * capture = cvCreateFileCapture(_video);
    IplImage * frame ;
    unsigned short count = 0 ;
    while (1){
        count ++ ;

       frame = cvQueryFrame(capture);
       if (count%3==0)
       {
            detect_result result = detect_yolo->to_detection(frame,0.45,0.5,0.5) ; 
            free_detections(result.dets, result.nboxes);
       }
      // char c = cvWaitKey(33);
       //if(c==27) break ;
    }
    cvReleaseCapture(&capture);
}

detect_obj.h

#pragma once 

#include 
#include 
#include 
#include 
#include "opencv2/opencv.hpp"
#include "highgui.h"


typedef struct {
    detection * dets;
    int nboxes ;
} detect_result ;

/*
use this class to detect the object from image(iplimage)
*/

class detect_obj {
public:
    explicit detect_obj();
    virtual  ~detect_obj();
    //load the trained yolo net 
    bool load_net(char *datacfg, char *cfgfile, char *weightfile,char * nameslist) ;
    // use the yolo net to detect the object before call this function, 
    //  you must called the load_net function 
    detect_result  to_detection(IplImage *_img ,float _nms , float _thresh, float _hier_thresh ) ; 

    
   /* detect_obj & operator = ( const detect_obj & _obj){
        if (&_obj ==this)
        {return *this;} };*/
protected:
    char **names ;
    image **alphabet ;
    network * net ;
    layer l_last ; 
};

detect_obj.cpp

#include "detect_obj.h"

detect_obj::detect_obj()
{
    //initilizing the member variable
    names = nullptr  ;
    alphabet =NULL;
    net = NULL ; 
    make_window("predictions", 512, 512, 0);
}
detect_obj::~detect_obj()
{   
    if(*names) delete *names;
    if (names) delete names ;
    if (*alphabet) delete *alphabet ;
    if (alphabet) delete alphabet ;
    if (net) delete net ;
    
}
/*****************************************************
name:bool detect_obj::load_net(char *datacfg, char *cfgfile, char *weightfile,char * nameslist)

input:
datacfg the info about data
cfgfile the architecture of model 
weightfile the parameters of the model 
nameslist the classes of data 

output:
bool if load the net correctly return true ,otherwise return false

function:load the network of yolo 
*********************************************************/
bool detect_obj::load_net(char *datacfg, char *cfgfile, char *weightfile,char * nameslist)
{
    list *options = read_data_cfg(datacfg) ; 
    char *name_list = option_find_str(options,"names",nameslist);
    names = get_labels(name_list) ; 

    alphabet = load_alphabet();
    net = load_network(cfgfile,weightfile,0);
    set_batch_network(net,1);
    srand(2222222);
    l_last = net->layers[net->n-1] ; 
    return true ;
}
/*****************************************************
name:bool detect_obj::to_detection(IplImage *_img,float _nms , float _thresh, float _hier_thresh )

input:
IplImage the image used to detect the object 
_nms if not zero ,will use this value to do nms operation
_thresh  the thresh of whether object or not 
_hier_thresh the same meaning with thresh ,i am not comprehensize 

output:
detect_result the object boxes and the classes ,the numbers of boxes

function:use the yolo model to detect object in object ,you must call net_load 
before call this function
*********************************************************/
detect_result detect_obj::to_detection(IplImage *_img,float _nms , float _thresh, float _hier_thresh )
{
    int h = _img->height ;
    int w = _img->width ;
    int c = _img->nChannels ;
    image im = make_image(w,h,c) ; 
    unsigned char *data = (unsigned char *)_img->imageData ;

    int step = _img->widthStep;

    int i,j,k;
    for (i = 0 ;iw,net->h) ; 
    double time ; 
    float *X = sized.data ;
    time = what_time_is_it_now();
    network_predict(net,X);
    printf("Predicted in %f seconds.\n",what_time_is_it_now()-time) ; 

    int nboxes = 0 ;

    detection *dets = get_network_boxes(net,im.w,im.h,_thresh,_hier_thresh,0,1,&nboxes);
    if(_nms) do_nms_sort(dets,nboxes,l_last.classes,_nms);
   
    detect_result result ;
    result.dets = dets ;
    result.nboxes = nboxes ;
    //for test 
    draw_detections(im, dets, nboxes, _thresh, names, alphabet, l_last.classes);


    //save_image(im, "predictions");
    
    show_image(im, "predictions", 1);
    free_image(im) ;
    free_image(sized) ; 
    //for test end 
    return result ;
}

对darknet自带的makefile进行更改,只编译自己写的程序,GPU版本,代码如下:

GPU=1
CUDNN=0
OPENCV=1
OPENMP=0
DEBUG=0

VPATH=./myproj2
SLIB=libdarknet.so
ALIB=libdarknet.a
EXEC=main2
OBJDIR=./myobj2/

CC=gcc
CPP=g++ -std=c++11
OPTS=-Ofast
LDFLAGS= -lm -pthread 
COMMON= -Iinclude/ -Isrc/
CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC

ifeq ($(OPENMP), 1) 
CFLAGS+= -fopenmp
endif

ifeq ($(DEBUG), 1) 
OPTS=-O0 -g
endif

CFLAGS+=$(OPTS)

ifeq ($(OPENCV), 1) 
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv` -lstdc++
COMMON+= `pkg-config --cflags opencv` 
endif

ifeq ($(GPU), 1) 
COMMON+= -DGPU -I/usr/local/neumoai/cuda8.0/include
CFLAGS+= -DGPU
LDFLAGS+= -L/usr/local/neumoai/cuda8.0/lib64 -lcuda -lcudart -lcublas -lcurand
endif

ifeq ($(CUDNN), 1) 
COMMON+= -DCUDNN 
CFLAGS+= -DCUDNN
LDFLAGS+= -lcudnn
endif

EXECOBJA= detect_obj.o main.o

ifeq ($(GPU), 1) 
LDFLAGS+= -lstdc++ 
endif

EXECOBJ = $(addprefix $(OBJDIR), $(EXECOBJA))

DEPS = $(wildcard myproj2/*.h) Makefile-myproj2 include/darknet.h

all: obj backup results  $(EXEC)
#all: obj  results $(SLIB) $(ALIB) $(EXEC)


$(EXEC): $(EXECOBJ) $(ALIB)
	$(CPP) $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(ALIB)

$(OBJDIR)%.o: %.cpp $(DEPS)
	$(CPP) $(COMMON) $(CFLAGS) -c $< -o $@

$(OBJDIR)%.o: %.c $(DEPS)
	$(CC) $(COMMON) $(CFLAGS) -c $< -o $@

$(OBJDIR)%.o: %.cu $(DEPS)
	$(NVCC) $(ARCH) $(COMMON) --compiler-options "$(CFLAGS)" -c $< -o $@

obj:
	mkdir -p myobj2



.PHONY: clean

clean:
	rm -rf  $(EXEC) $(EXECOBJ)

需要对库的路径及头文件的路径进行修改,符合自己的工程的需要,推荐在darknet源文件中。
之前写了个cmakefile.txt的,cpu版本的库调用没有问题,gpu版本的库调用有问题,后来发现应该是没有指定-DGPU宏定义,大家也可以用cmakelist.txt。

你可能感兴趣的:(yolo)