为了方便代码中调用,本文将yolov3源码封装。代码原始版本为windows版本https://github.com/AlexeyAB/darknet。
主要是方便c++/c用户。调用测试案例代码为main.cpp。添加在控制台敲指令的功能,输入stop停止程序。
1.在darknet-master/src文件夹下面添加三个文件,yolov3.cpp,yolov3.h,main.cpp
2.vs打开darknet.sln,添加现有项darknet->添加->现有项,将yolov3.cpp,yolov3.h,main.cpp添加进去
3.将image.c中的draw_detections_v3函数修改为
static box detect_res[128];/*检测的结果*/
static int detect_nums;/*检测出来的目标个数*/
int get_detect_res(box* res)
{
assert(res != NULL);
memcpy(res, detect_res, sizeof(box)*detect_nums);
return detect_nums;
}
void draw_detections_v3(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes, int ext_output)
{
static int frame_id = 0;
frame_id++;
int selected_detections_num;
detection_with_class* selected_detections = get_actual_detections(dets, num, thresh, &selected_detections_num, names);
// text output
qsort(selected_detections, selected_detections_num, sizeof(*selected_detections), compare_by_lefts);
int i;
for (i = 0; i < selected_detections_num; ++i) {
const int best_class = selected_detections[i].best_class;
printf("%s: %.0f%%", names[best_class], selected_detections[i].det.prob[best_class] * 100);
if (ext_output)
printf("\t(left_x: %4.0f top_y: %4.0f width: %4.0f height: %4.0f)\n",
round((selected_detections[i].det.bbox.x - selected_detections[i].det.bbox.w / 2)*im.w),
round((selected_detections[i].det.bbox.y - selected_detections[i].det.bbox.h / 2)*im.h),
round(selected_detections[i].det.bbox.w*im.w), round(selected_detections[i].det.bbox.h*im.h));
else
printf("\n");
int j;
for (j = 0; j < classes; ++j) {
if (selected_detections[i].det.prob[j] > thresh && j != best_class) {
printf("%s: %.0f%%\n", names[j], selected_detections[i].det.prob[j] * 100);
}
}
}
// image output
qsort(selected_detections, selected_detections_num, sizeof(*selected_detections), compare_by_probs);
int ai_nums = 0;
for (i = 0; i < selected_detections_num; ++i) {
int width = im.h * .006;
if (width < 1)
width = 1;
int offset = selected_detections[i].best_class * 123457 % classes;
float red = get_color(2, offset, classes);
float green = get_color(1, offset, classes);
float blue = get_color(0, offset, classes);
float rgb[3];
//width = prob*20+2;
rgb[0] = red;
rgb[1] = green;
rgb[2] = blue;
box b = selected_detections[i].det.bbox;
//printf("%f %f %f %f\n", b.x, b.y, b.w, b.h);
int left = (b.x - b.w / 2.)*im.w;
int right = (b.x + b.w / 2.)*im.w;
int top = (b.y - b.h / 2.)*im.h;
int bot = (b.y + b.h / 2.)*im.h;
if (left < 0) left = 0;
if (right > im.w - 1) right = im.w - 1;
if (top < 0) top = 0;
if (bot > im.h - 1) bot = im.h - 1;
//float x, y, w, h;
detect_res[ai_nums].x = left;
detect_res[ai_nums].y = top;
detect_res[ai_nums].w = right - left;
detect_res[ai_nums].h = bot - top;
ai_nums++;
#if 0
if (im.c == 1) {
draw_box_width_bw(im, left, top, right, bot, width, 0.8); // 1 channel Black-White
}
else {
draw_box_width(im, left, top, right, bot, width, red, green, blue); // 3 channels RGB
}
if (alphabet)
{
char labelstr[4096] = { 0 };
strcat(labelstr, names[selected_detections[i].best_class]);
int j;
for (j = 0; j < classes; ++j) {
if (selected_detections[i].det.prob[j] > thresh && j != selected_detections[i].best_class) {
strcat(labelstr, ", ");
strcat(labelstr, names[j]);
}
}
image label = get_label_v3(alphabet, labelstr, (im.h*.03));
draw_label(im, top + width, left, label, rgb);
free_image(label);
}
#endif
if (selected_detections[i].det.mask) {
image mask = float_to_image(14, 14, 1, selected_detections[i].det.mask);
image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
image tmask = threshold_image(resized_mask, .5);
embed_image(tmask, im, left, top);
free_image(mask);
free_image(resized_mask);
free_image(tmask);
}
}
detect_nums = ai_nums;
free(selected_detections);
}
在image.h中添加int get_detect_res(box* res);
4.yolov3.cpp
#include "yolov3.h"
#include "image_opencv.h"
#include
#include
static char **names;
image mat_to_image(cv::Mat mat)
{
int w = mat.cols;
int h = mat.rows;
int c = mat.channels();
image im = make_image(w, h, c);
unsigned char *data = (unsigned char *)mat.data;
int step = mat.step;
for (int y = 0; y < h; ++y) {
for (int k = 0; k < c; ++k) {
for (int x = 0; x < w; ++x) {
//uint8_t val = mat.ptr(y)[c * x + k];
//uint8_t val = mat.at(y, x).val[k];
//im.data[k*w*h + y*w + x] = val / 255.0f;
im.data[k*w*h + y*w + x] = data[y*step + x*c + k] / 255.0f;
}
}
}
return im;
}
darknet::darknet()
{
}
darknet::~darknet()
{
}
void darknet::cuda_init(int gpuid)
{
cuda_set_device(gpuid);
CHECK_CUDA(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync));
}
void darknet::file_init(char* datacfg, char* netcfg, char* weightscfg)
{
strcpy(data_file,datacfg);
strcpy(net_file, netcfg);
strcpy(weight_file, weightscfg);
}
void darknet::param_init(float conf, float hier_thr, float nms)
{
thresh = conf;
hier_thresh = hier_thr;
Non_maximum = nms;
}
void darknet::net_init(char* datacfg, char* netcfg, char* weightscfg)
{
options = read_data_cfg(datacfg);
char *name_list = option_find_str(options, "names", "data/names.list");
int names_size = 0;
names = get_labels_custom(name_list, &names_size); //get_labels(name_list);
alphabet = load_alphabet();
net = parse_network_cfg_custom(netcfg, 1, 1); // set batch=1
//getchar();
load_weights(&net, weightscfg);
net.benchmark_layers = 0;
fuse_conv_batchnorm(net);
calculate_binary_weights(net);
if (net.layers[net.n - 1].classes != names_size) {
printf(" Error: in the file %s number of names %d that isn't equal to classes=%d in the file %s \n",
name_list, names_size, net.layers[net.n - 1].classes, netcfg);
if (net.layers[net.n - 1].classes > names_size) getchar();
}
}
cv::Mat darknet::resize_mat(const cv::Mat& src)
{
int rows = src.rows;
int cols = src.cols;
int max_lens = std::max(rows, cols);
cv::Mat new_mat = cv::Mat::zeros(max_lens, max_lens, src.type());
src.copyTo(new_mat(cv::Rect(0, 0, cols, rows)));
cv::resize(new_mat, new_mat, cv::Size(net.w, net.h));
return new_mat;
}
image darknet::change_mat2_image(cv::Mat src)
{
//mat_cv mat_address = (mat_cv)&src;
return mat_to_image(src);
//return mat_to_image_cv(&mat_address);
}
void darknet::box_2_cvrect(box* detres, int lens, cv::Rect* res)
{
assert(detres != NULL);
assert(res != NULL);
for (int i = 0; i < lens; i++)
{
res[i].x = (int)detres[i].x;
res[i].y = (int)detres[i].y;
res[i].width = (int)detres[i].w;
res[i].height = (int)detres[i].h;
}
}
int darknet::detect_mat(cv::Mat src, cv::Rect* res)
{
image im = change_mat2_image(src);
image sized = resize_image(im, net.w, net.h);
layer l = net.layers[net.n - 1];
float *X = sized.data;
//getchar();
network_predict(net, X);
//printf("%s: Predicted in %lf milli-seconds.\n", input, ((double)get_time_point() - time) / 1000);
int nboxes = 0;
detection *dets = get_network_boxes(&net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes, 0);//letter_box
if (Non_maximum) {
if (l.nms_kind == DEFAULT_NMS) do_nms_sort(dets, nboxes, l.classes, Non_maximum);
else diounms_sort(dets, nboxes, l.classes, Non_maximum, l.nms_kind, l.beta_nms);
}
draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, 0);
box detectres[128];
int detect_lens = get_detect_res(detectres);
box_2_cvrect(detectres, detect_lens, res);
free_detections(dets, nboxes);
free_image(im);
free_image(sized);
return detect_lens;
}
void darknet::exit()
{
free_ptrs((void**)names, net.layers[net.n - 1].classes);
free_list_contents_kvp(options);
free_list(options);
int i;
const int nsize = 8;
for (int j = 0; j < nsize; ++j) {
for (i = 32; i < 127; ++i) {
free_image(alphabet[j][i]);
}
free(alphabet[j]);
}
free(alphabet);
free_network(net);
}
5.yolov3.h
#pragma once
#ifndef _YOLO_V3_H_HH
#define _YOLO_V3_H_HH
#include "darknet.h"
#include "network.h"
#include "region_layer.h"
#include "cost_layer.h"
#include "utils.h"
#include "parser.h"
#include "box.h"
#include "demo.h"
#include "option_list.h"
#include
#include
class darknet
{
public:
darknet();
virtual ~darknet();
public:
void cuda_init(int gpuid);
/*设置参数*/
void file_init(char* datacfg, char* netcfg, char* weightscfg);
void param_init(float conf, float hier_thr, float nms);
/*网络初始化*/
void net_init(char* datacfg, char* netcfg, char* weightscfg);
/*检测结果*/
int detect_mat(cv::Mat src, cv::Rect* res);
void exit();
protected:
cv::Mat resize_mat(const cv::Mat& src);
//void load_model();
image change_mat2_image(cv::Mat src);/*将mat转为image*/
void box_2_cvrect(box* detres, int lens, cv::Rect* res);
private:
char data_file[128];
char net_file[128];
char weight_file[128];
float thresh;/*置信度阈值*/
float hier_thresh;
float Non_maximum;
private:
network net;
image **alphabet;
list *options;
};
#endif
6.main.cpp
#include "yolov3.h"
#include
#include
#include
std::atomic_bool runflag;
#if 1
void test_detect()
{
//darknet* det = new darknet();
darknet* det = new darknet();
det->cuda_init(0);
char* datacfg = (char*)"x64\\data\\coco.data";
char* netcfg = (char*)"x64\\yolov3.cfg";
char* weightscfg = (char*)"x64\\yolov3.weights";
det->param_init(0.25, 0.5, 0.45);
//system("pause");
det->net_init(datacfg, netcfg, weightscfg);
cv::VideoCapture cap;
cap.open(0);
cv::Mat frame;
int detect_lens;
cv::Rect res[128];
while (cap.read(frame))
{
if (!runflag)break;
detect_lens = det->detect_mat(frame, res);
for (int i = 0; i < detect_lens; i++) {
cv::rectangle(frame, res[i], cv::Scalar(255, 0, 0), 2, 8);
}
cv::imshow("det.jpg", frame);
cv::waitKey(20);
}
det->exit();
delete det;
cap.release();
//return 0;
}
#endif
void test_image(const cv::Mat& src)
{
darknet* det = new darknet();
det->cuda_init(0);
//char* datacfg = "cfg\\coco.data";
char* datacfg = (char*)"x64\\data\\coco.data";
char* netcfg = (char*)"x64\\yolov3.cfg";
char* weightscfg = (char*)"x64\\yolov3.weights";
det->param_init(0.25, 0.5, 0.45);
//system("pause");
det->net_init(datacfg, netcfg, weightscfg);
//system("pause");
cv::Rect res[128];
int detect_lens = det->detect_mat(src, res);
printf("error 06\n");
//system("pause");
cv::Mat src_copy = src.clone();
for (int i = 0; i < detect_lens; i++) {
cv::rectangle(src_copy, res[i], cv::Scalar(255, 0, 0), 2, 8);
}
cv::imshow("det.jpg", src_copy);
cv::waitKey(0);
det->exit();
delete det;
}
void console()
{
char words[128];
while (runflag)
{
scanf_s("%s", words);
if (!strcmp(words, "stop"))
{
runflag = false;
break;
}
Sleep(10);
}
}
int main(int argc, char** argv)
{
runflag = true;
std::thread console_thread = std::thread(console);
cv::Mat src = cv::imread("x64\\dog.jpg");
test_detect();
if (console_thread.joinable()) console_thread.join();
//test_image(src);
return 0;
}
7.将darknet.c中的main函数改为t_main。重新编译即可。
本代码没有添加目标标注目标类型,简单调用opencv画矩形的接口,朋友们可以自己动手添加目标类型画在矩形框上面。