【DL-YOLO】尝鲜!Windows下实现YOLOv4物体检测(VS2015+OpenCV)
https://mp.weixin.qq.com/s?__biz=MzU3MzI2NDcyNg==&mid=2247484799&idx=1&sn=61ba7eb266190dc00125a8a72c57cf3b&chksm=fcc50346cbb28a50028ad5365593264ff406d3a0446aa7ed30f35f77965d38e61b01f7648299&scene=21#wechat_redirect
戳一戳!和我一起走进深度学习的世界
导读
想必很多人都听说过大名鼎鼎的YOLO。我19年本科毕业,18年初次接触YOLO,现在已经两年过去了,前不久,YOLO最新版本,YOLOv4腾空出世,很多人争相投入YOLO的怀抱,来感受YOLO带给我们的温存。
这篇文章,我们不讲别的,我们不讲原理,不讲论文,不讲历史,说白了,就是,我们不讲“废话。我们带领大家一起,在Windows系统下,以VS2015和opencv为基础,利用YOLO的代码,做物体检测。
如果你是初次了解YOLO,你可以看我以后的文章介绍,或者先不管这个是干嘛的,实现了再说。如果你已经有所了解,那就不要扯虚的,直接正题,开始实战。如果你熟练掌握YOLO,欢迎对我的做法提出宝贵意见。
如果大家想了解更多有关YOLO的文章,可以点击最后的阅读原文关注我的博客
目录
导读
1 准备工作
A 下载
B 环境要求
2 配置
A OpenCV配置
B YOLO配置
C 项目配置
3 代码实战
A 文件搬家
B 文件修改
C 代码编写
4 说在后面的话
如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就加群:326866692 或者扫描下方二维码加入我们吧!
1 准备工作
A 下载
当然第一件事应该是先下载:这里给大家提供两个下载,一个是论文下载,一个是源码下载。当然这些文件也可以加上面的群进行下载。
论文:https://arxiv.org/abs/2004.10934
源码:https://github.com/AlexeyAB/darknet
注意,在源码中,我们还要下载权重文件:
https : //drive.google.com/open?id=1cewMfusmPjYWbrnuJRuKhPMwRe_b9PaT
B 环境要求
这个操作,我们只需要一台Windows系列的电脑,建议使用Windows10。
然后,我们需要安装VS2015以及opencv4.3.0。
VS2015要求支持编写C++代码。
对于opencv来说,理论上建议大家使用3.0以上版本。
2 配置
在这一部分,我们进行环境配置讲解。
注意,做完前两个配置之后,最好重启一下电脑。
A OpenCV配置
安装OpenCV,我们会发现,在我们的安装路径下,是这样的:
OpenCV4.3.0安装结果
在我们的代码中,其实我们只需要build文件夹中的内容:
build文件夹
按照【计算机】->【(右键)属性】->【高级系统设置】->【高级(标签)】->【环境变量】->“双击”系统变量中的PATH->在变量值里面添加相应的路径。
环境变量配置
在路径配置中填写 ”…… opencvuildx64vc14in”,很多人发现,X64中有两个文件夹:
VC14与VC15
这个表示OpenCV和VS的对应关系,详细的对应关系如下:
OpenCV与VS对应关系
因为我们是VS2015,所以我们使用VC14这个文件夹的。 我们打开这个文件夹,我们发现这个文件夹有如下的文件:
vc14文件夹
我们要把bin文件夹路径存到我们的系统变量中。bin文件中有两个dll文件,我们需要把这两个dll文件复制到C:WindowsSysWOW64这个文件夹下。
dll文件
B YOLO配置
这个配置指的是我们在系统中需要的配置。
我们先把Darknet解压,Darknet文件夹内容如下,东西有很多:
Darknet文件
我们发现这里有个3rdparty文件夹,我们按照3rdpartypthreadsin这个路径,打开,将这个路径也存到环境变量中,加上前面的OpenCV,如下图:
3rdparty环境变量配置
然后将这个文件夹下的dll文件,复制到C:WindowsSysWOW64这个文件夹下。
C 项目配置
我们打开VS2015,创建一个空项目,记住,我们要把安全检查去掉。
空项目,不要安全检查
然后我们点击项目,选择属性,进行属性配置:
属性配置界面
我们选择VC++目录,我们在包含目录中,将OpenCV下面的两个包含文件路径存到里面。分别是:
“...opencvuildinclude”;
“...opencvuildincludeopencv2”
将3rdparty下面的pthread的包含文件路径存到里面:
“...3rdpartypthreadsinclude”
效果如下:
包含目录配置
下面还有一个库目录,配置一样的,配置的内容为OpenCV的:
“...opencvuildx64vc14lib”
pthread的:
“...3rdpartypthreadslib”
效果如下:
库目录配置
然后我们在链接器中选择输入,在附加依赖项中添加上面两个库目录中的lib文件:
opencv_world430.lib
opencv_world430d.lib
pthreadVC2.lib
附加依赖项
注意:
对于OpenCV来说,如果使用debug模式,用带d的,使用release模式,用不带d的。对于我们的项目来说,在release模式下不会报错,所以我们一般使用不带d的。
3 代码实战
配置完成之后,就该我们最重要的环节了,哈哈哈,大家开心不?
好吧,开心不开心,其实不重要,只要我们能够得到结果就会开心对不对。
A 文件搬家
我们打开Darknet项目,我们发现Darknet文件夹中有src这个文件夹:
src文件夹
我们需要把这个文件夹下面的C语言和C++语言文件,都复制到我们的项目中。
复制到项目中
大家有没有印象,我们在3rdparty中还有一个stb文件夹,我们打开include文件夹,把下面这两个文件也保存在我们的项目中。
stb包含文件
然后我们打开Darknet的include文件夹,将里面的两个文件,也复制到我们的项目中:
Darknet包含文件
然后,我们可以把我们下载下来的cfg配置文件和权重文件还有coco数据集名称文件全部放在这个文件夹中。
模型相关文件
然后我们提前准备好一张图片,也放在这个文件夹下面,方便我们一会代码使用:
测试图片
B 文件修改
代码拿来是不能直接用的,需要我们做一些修改,主要包括如下几方面:
1.time.h修改为timeb.h
我们分别打开demo.c,classifier.c和art.c文件,我们发现,在最上面有如下代码:
我们把这块代码改为:
2.darknet.c修改
我们打开darknet.c文件,将里面的主函数修改名称,比如darknet_main:
int main(int argc, char **argv)
我们把这块代码改为:
int darknet_main(int argc, char **argv)
3.gemm.c修改
找到第510行,将:
int tmp_count = __builtin_popcount(val32);
修改为:
int tmp_count = __popcnt(val32);
因为我们是在Windows下做,上面的那个是Linux系统下的。
修改完上面的这三部分,就可以生成解决方案了,如果显示生成成功1个,失败0个,那我们就准备工作完全做完啦:
生成解决方案
C 代码编写
在这个项目中是还是有个主函数的。在yolo_console_dll.cpp中,这个也是源代码中的测试主函数。
为了方便,我们就直接将这个文件中的内容删掉,写我们自己的代码,当然里面的一些函数是用的原来这个文件的,但是为了方便我们讲解,我们就重头说起。
首先,我们需要一些头文件:
using namespace cv;
using namespace std;
这个没啥,接下来我们编写主函数,我么想一下,我们利用模型做检测其实就是如下几步:
·加载数据集类别名
·加载模型
·加载图片
·图片检测与效果展示
这些代码如下:
int main() {
//类别名称加载
std::string names_file = "coco.names";
auto obj_names = objects_names_from_file(names_file);
//模型加载
std::string cfg_file = "yolov4.cfg";
std::string weights_file = "yolov4.weights";
Detector detector(cfg_file, weights_file);
//图片加载
std::string filename = "1.png";
Mat show_img = imread(filename);
auto img = detector.load_image(filename);
imshow("init_img", show_img);
//检测与显示
std::vector<bbox_t> result_vec = detector.detect(img);
show_console_result(result_vec, obj_names);
draw_boxes(show_img, result_vec, obj_names);
waitKey(0);
return 0;
}
在这里我们用到了几个函数,这几个函数有的是源代码中的,有的是我自己修改后的,我把每个函数分享给大家:
//画边框
void draw_boxes(cv::Mat mat_img, std::vector<bbox_t> result_vec, std::vector<std::string> obj_names)
{
int k = 0;
for (auto &i : result_vec) {
Scalar color = Scalar(k, (k + 100) % 256, 255 - k);
k = (k + 47) % 255;
cv::rectangle(mat_img, cv::Rect(i.x, i.y, i.w, i.h), color, 2);
if (obj_names.size() > i.obj_id) {
std::string obj_name = obj_names[i.obj_id];
putText(mat_img, obj_name, cv::Point2f(i.x, i.y - 16), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, color, 2);
}
}
imshow("result", mat_img);
}
//展示结果
void show_console_result(std::vector<bbox_t> const result_vec, std::vector<std::string> const obj_names, int frame_id = -1) {
if (frame_id >= 0) std::cout << " Frame: " << frame_id << std::endl;
for (auto &i : result_vec) {
if (obj_names.size() > i.obj_id) std::cout << obj_names[i.obj_id] << " - ";
std::cout << "obj_id = " << i.obj_id << ", x = " << i.x << ", y = " << i.y << ", w = " << i.w << ", h = " << i.h << std::setprecision(3) << ", prob = " << i.prob << std::endl;
}
}
//获取目标名称
std::vector<std::string> objects_names_from_file(std::string const filename) {
std::ifstream file(filename);
std::vector<std::string> file_lines;
if (!file.is_open()) return file_lines;
for (std::string line; getline(file, line);) file_lines.push_back(line);
std::cout << "object names loaded ";
return file_lines;
}
做完上面的,我们就可以做检测了,效果如下:
检测效果
如果大家想要项目的全部代码,可以加群下载!4 说在后面的话
我接触到的第一个深度学习框架,就是YOLO,所以对它有种特殊的感情,于是我暂放下手中的工作,全身心扑到它上面。
我曾经尝试过用我以前写的一个框架直接调用YOLOv4的模型,但是总是报错。原因是v4中使用的激活函数在OpenCV中找不到,所以不行,因此我就转头研究了他的源代码。
其实我很感谢他使用了OpenCV中没有的激活函数,这让我不得不放下我之前做好的,重新开始,如果我使用了以前的,我只需要修改一下文件即可,得到了短暂的快乐,并没有深入的收获。但这次,我对这个框架理解更深刻了。
通过这件事,我想说,人这一生,一定要找到一个能让自己喜欢的事,并且全身心投入到里面,只有真的喜欢,才能真正从里面找到乐趣,才能抵抗他给我们带来的磨难。在追求兴趣的道路上,不可能是一帆风顺的,一定会有波折,会有坎坷,我们不能因为这个坎坷就让我们放下我们对自己所喜爱的东西的追求,相反,我们应该感谢这一次次的磨难,他们不仅能让我们得到成长,也更让我们热爱自己所热爱的,能让我们无悔此生。
我一直说,我想做一个布道者,什么是布道者,在我看来,布道者就是一个坚定自己理想信念,并且能够给他人带来正能量,能够通过自己的努力让别人过得更好的人。所以我希望,你们看我的博客不仅仅要学到技术,更要学到技术之外我想表达的。因为,讲技术的很多,讲的比我好的更多,但是愿意在讲技术的同时说一些感悟,讲一些哲理的不多。
希望你们能有所收获,有所成长。这就是我努力的意义。