目前开源的车辆检测模型主要是针对白天场景,夜晚的车辆检测基本找不到。由于项目需要,只好自己训练了一个基于YOLO的夜间车辆检测模型。
采用的网络结构car.cfg:
[net]
# Testing
#batch=1
#subdivisions=1
# Training
batch=64
subdivisions=4
width=512
height=512
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 5000
policy=steps
steps=3800,4500
scales=.1,.1
[convolutional]
batch_normalize=1
filters=16
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=32
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
#########################
### SPP ###
[maxpool]
stride=1
size=5
[route]
layers=-2
[maxpool]
stride=1
size=9
[route]
layers=-4
[maxpool]
stride=1
size=13
[route]
layers=-1,-3,-5,-6
### End SPP ###
#########################
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[convolutional]
size=1
stride=1
pad=1
filters=21
activation=linear
[yolo]
mask = 6,7,8
anchors = 16, 21, 21, 28, 27, 37, 34, 49, 42, 67, 58, 84, 64,112, 85,131, 128,242
classes=2
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
scale_x_y = 1.05
iou_thresh=0.213
cls_normalizer=1.0
iou_normalizer=0.07
iou_loss=ciou
nms_kind=greedynms
beta_nms=0.6
max_delta=5
[route]
layers = -4
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[upsample]
stride=2
[route]
layers = -1, 8
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
size=1
stride=1
pad=1
filters=21
activation=linear
[yolo]
mask = 3,4,5
anchors = 16, 21, 21, 28, 27, 37, 34, 49, 42, 67, 58, 84, 64,112, 85,131, 128,242
classes=2
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
scale_x_y = 1.05
iou_thresh=0.213
cls_normalizer=1.0
iou_normalizer=0.07
iou_loss=ciou
nms_kind=greedynms
beta_nms=0.6
max_delta=5
[route]
layers = -4
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[upsample]
stride=2
[route]
layers = -1, 6
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[convolutional]
size=1
stride=1
pad=1
filters=21
activation=linear
[yolo]
mask = 0,1,2
anchors = 16, 21, 21, 28, 27, 37, 34, 49, 42, 67, 58, 84, 64,112, 85,131, 128,242
classes=2
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
scale_x_y = 1.05
iou_thresh=0.213
cls_normalizer=1.0
iou_normalizer=0.07
iou_loss=ciou
nms_kind=greedynms
beta_nms=0.6
max_delta=5
训练之后,模型的测试效果还行
#include "stdafx.h"
#include
#include
#include
#include
#include
using namespace cv;
using namespace dnn;
using namespace std;
float confThreshold = (float) 0.50;
float nmsThreshold = (float) 0.50;
vector classes;
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);
/*************************************************
函数名:
函数描述:
输入参数:
输出参数:
返回值:
**************************************************/
vector getOutputsNames(const dnn::Net& net)
{
static vector names;
if (names.empty())
{
vector outLayers = net.getUnconnectedOutLayers();
vector layersNames = net.getLayerNames();
names.resize(outLayers.size());
for (size_t i = 0; i < outLayers.size(); ++i)
names[i] = layersNames[outLayers[i] - 1];
}
return names;
}
/*************************************************
函数名:
函数描述:
输入参数:
输出参数:
返回值:
**************************************************/
void postprocess(Mat& frame, vector& outs)
{
vector classIds;
vector confidences;
vector boxes;
for (size_t i = 0; i < outs.size(); ++i)
{
float* data = (float*)outs[i].data;
for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
{
Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
Point classIdPoint;
double confidence;
minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
int centerX = (int)(data[0] * frame.cols);
int centerY = (int)(data[1] * frame.rows);
int width = (int)(data[2] * frame.cols);
int height = (int)(data[3] * frame.rows);
int left = centerX - width / 2;
int top = centerY - height / 2;
classIds.push_back(classIdPoint.x);
confidences.push_back((float)confidence);
boxes.push_back(Rect(left, top, width, height));
}
}
vector indices;
dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
for (size_t i = 0; i < indices.size(); ++i)
{
int idx = indices[i];
Rect box = boxes[idx];
drawPred(classIds[idx], confidences[idx], box.x, box.y,
box.x + box.width, box.y + box.height, frame);
}
}
/*************************************************
函数名:
函数描述:
输入参数:
输出参数:
返回值:
**************************************************/
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
{
//标签值初始化为置信度
string label = format("%.2f", conf);
if (classId == 0) {
rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 255, 0), 2);
putText(frame, label, Point(right + 10, top + 40), FONT_HERSHEY_COMPLEX, 0.4, Scalar(0, 255, 0), 1, 0);
}//车头
else {
rectangle(frame, Point(left, top), Point(right, bottom), Scalar(255, 255, 0), 2);
putText(frame, label, Point(right + 10, top + 40), FONT_HERSHEY_COMPLEX, 0.4, Scalar(255, 255, 0), 1, 0);
}//车尾
}
/*************************************************
函数名:
函数描述:
输入参数:
输出参数:
返回值:
**************************************************/
int main()
{
clock_t startTime, endTime;
String modelConfiguration = "./model/car.cfg";
String modelBinary = "./model/car.weights";
Net net = readNetFromDarknet(modelConfiguration, modelBinary);
if (net.empty())
{
printf("Could not load net...\n");
return 0;
}
int i = 1000;//测试图片数量
int j = 0;
string path;
Mat frame;
cvNamedWindow("image", 0);
resizeWindow("image", 1400, 800);
while (j < i)
{
startTime = clock();
// 加载图像
path = "./valid/" + to_string(j) + ".jpg";
startTime = clock();
frame = imread(path);
if (frame.empty()) {
j++;
continue;
}
Mat blob;
dnn::blobFromImage(frame, blob, 1 / 255.0, Size(512, 512), Scalar(0, 0, 0), true, false);
net.setInput(blob);
vector outs;
net.forward(outs, getOutputsNames(net));
postprocess(frame, outs);//获取最后一层输出;
Mat detectedFrame;
frame.convertTo(detectedFrame, CV_8U);
imshow("image", detectedFrame);
endTime = clock();
cout << "Totle Time : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
waitKey();
j++;
}
destroyWindow("image");
return 0;
}
实际测试效果