yolov3源码封装

yolov3源码封装

为了方便代码中调用,本文将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 <string.h>
#include <stdio.h>
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<uint8_t>(y)[c * x + k];
				//uint8_t val = mat.at<Vec3b>(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 <opencv2/opencv.hpp>
#include <string>

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 <atomic>
#include<windows.h>
#include <thread>

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画矩形的接口,朋友们可以自己动手添加目标类型画在矩形框上面。

发布了35 篇原创文章 · 获赞 13 · 访问量 6323

猜你喜欢

转载自blog.csdn.net/qq_35306281/article/details/104086046