Darknet 分类器
出于对Darknet框架下YOLO结构的火热,网络上一堆关于目标检测的C++调用形式和模板,但是未曾存在C++调用分类器的模板,故采用如下形式,展开阐述。
Darknet出名的为目标检测网络,但是遗忘了其中的构建基础的分类网络方式,没有得到很好的利用
大致步骤可参考
训练过程和标注样本数据的方式参考如下文章:
https://blog.csdn.net/u011576009/article/details/70146766
中间出现的需要生成和修改的文件为,
数据集准备
train.list
格式为路径指向训练文件,/home/ubuntu/data/train/D250252_00001.jpg的形式
其中D250252为类别号
val.lilst
同train.list
label.list
只存在类别 如:D250252等
name.list
对类别号的映射过程,训练过程中不采用。
网络搭建
构建主要参考cifar 搭建了 lenet-5的分类网络,速度及其快,1080ti 1ms完成分类任务测试
需要更改为一个.cfg文件
一个data文件 指向训练集,测试集和类别号等等
跑网络使用的command
./darknet classifier train cfg/mnist.data cfg/mnist.cfg
测试单张图片
./darknet classifier predict cfg/market1501.data cfg/mobilenet_1501_train.cfg backup/mobilenet_1501_train_100.weights data/train/0007_aabbc1.jpg
测试Val数据集
./darknet classifier valid cfg/market1501.data cfg/mobilenet_1501_test.cfg backup/mobilet_v2/mobilenet_1501_train_787.weights
出现的Issue:
1、Train的过程中出现Too many or too few arguments
参考github中issues:
https://github.com/pjreddie/darknet/issues/833
- 修改了源码,但是测试过程,还是出现分类报错问题
fill_truth function in src/data.c file
void fill_truth(char *path, char **labels, int k, float *truth)
{
int i;
char *filename = "";
for (i = strlen(path) - 1; i >= 0; --i) {
if (path[i] == '/' || path[i] == '\\') {
filename = (char*)malloc(strlen(path + i) + 1);
strcpy(filename, path + i + 1);
break;
}
}
memset(truth, 0, k*sizeof(float));
int count = 0;
for(i = 0; i < k; ++i){
if(strstr(filename, labels[i])){
truth[i] = 1;
++count;
//printf("%s %s %d\n", path, labels[i], i);
}
}
if(count != 1 && (k != 1 || count != 0)) printf("Too many or too few labels: %d, %s\n", count, path);
}
- 后参考另一个issues
提及到,路径和类别不能出现一样的字符,将会导致判定失误,改完以后,成功完成训练过程。
C++调用方式
使用编译完成libdarnet.so配合cuda的动态库,再加头文件darknet.h 即可调用
主要关键使用在于分类网络的输出问题,网络的输入采用接口的形式
主要参考代码为darknet源码中cuda.c classfier.c darnet.c等内容
参考Yolo调用模板格式:
https://blog.csdn.net/weixin_33860450/article/details/84890877
其中较为关键的是img_preprocess 问题
imgprocess.hpp
#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
imgprocess.cpp
#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);
}
main.cpp(模板如下)
network *net = load_network();
// img pre process resize ,convert malloc space
float *predictions = network_predict(*net,resizeImg);
top_k(predictions,(*net).outputs,top,indexes);
//output the index
int index = indexes[0];
predictions[index];
参考形式如下形式:把yolo的输出形式换成上述模板内容,即可完成分类预测任务。
#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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)