本次要整理的内容是:在OpenCV中使用dnn模块来调用MobileNetSSD神经网络模型,并实现常见目标检测。MobileNetSSD,顾名思义是一个适用于移动端的ssd神经网络模型,其运行速度是比较可观的,可以用在实时检测当中。在本次笔记中,先使用一张图像作为演示,传入MobileNetSSD模型中并进行识别,然后再调用笔记本自带的摄像头实现一个实时的常见目标检测。
对于MobileNetSSD模型,由于比较轻量化,所以它提高运行速度的同时,却只能对二十种常见物品进行检测,下面所列出的清单是MobileNetSSD模型的标签集。(有一说一,牛马这些真的是常见目标吗。。。)
背景
飞机、自行车、鸟、船、瓶子、总线、汽车、猫、椅子、牛、餐桌、狗、马、摩托车、人、盆栽、羊、沙发、火车、电视监视器
下面开始通过代码逐步实现。
首先我们需要加载MobileNetSSD模型
string model_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\ssd\\MobileNetSSD_deploy.caffemodel";
string config_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\ssd\\MobileNetSSD_deploy.prototxt";
string label_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\ssd\\labels.txt";
Net MobileNetSSD = readNetFromCaffe(config_path, model_path);
然后设置dnn模块的计算后台和目标设备,在我的电脑上测试不同的设置方式,实时FPS效果如下: CUDA+CUDA > INFERENCE_ENGINE+CPU > OPENCV+OPENCL > OPENCV+CPU.
所以如果有N系显卡的朋友还是最好使用CUDA来加速吧,如果不行的话,英特尔的openVINO也是一个不错的选择。
MobileNetSSD.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
MobileNetSSD.setPreferableTarget(DNN_TARGET_CPU);
然后再加载标签集
//加载标签集
ifstream fp(label_path);
if (!fp.is_open())
{
cout << "model file open fail" << endl;
}
vector<string> labels;
while (!fp.eof())
{
string label_name;
getline(fp, label_name);
labels.push_back(label_name);
}
fp.close();
接着读取测试图像,并转换为4维blob传入MobileNetSSD模型中进行前向传播。
前向传播结果是一个四维矩阵prob,第一维是输入图像编号、第二维是输入图像数量、第三维是检测的每个目标、第四维是每个目标的信息,包含类别ID、置信度、目标框的左上角和右下角坐标点等,其中坐标是该点相对于图像宽高的比例。
对于单独一张输入测试图像,prob的第一维度和第二维度的值都是1。我们需要的信息是第三维度和第四维度,所以将第三和第四维度组织成Mat对象,即检测结果矩阵。在这里,我们将得到的4维前向传播结果矩阵prob转换为2维预测结果矩阵detection。
Mat test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\CC4.jpg");
resize(test_image, test_image, Size(800, 600));
Mat inputBlob = blobFromImage(test_image, 0.008, Size(300, 300), Scalar(127.5, 127.5, 127.5), true