上篇文章中使用了SSD模型进行对象检测,虽然没有说明模型运行时间,但是ssd是非常耗时的,速度有点慢,因为它的支持数目比较多。而MobileNet其实就是ssd的删减版,运作速度有所提升,但支持的检测对象比较少。所以它是一种轻量级网络,主要应用于移动端。
具体需参考以下文章:https://blog.csdn.net/u011974639/article/details/79199306
https://blog.csdn.net/wfei101/article/details/78310226
上面说到,mobilenet是ssd的精简版,所以在代码层面上没有什么变化,只是一些参数有少许变化。
完整代码:
#include<opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>
#include<iostream>
using namespace cv;
using namespace std;
using namespace cv::dnn;
const size_t width = 300;
const size_t height = 300;//定义图像文件宽高
vector<String> labels();
string label_file = "D:/test/ssd/mobilenet-ssd/labelmap.txt";
string deploy_file = "D:/test/ssd/mobilenet-ssd/MobileNetSSD_deploy.prototxt";
string model_file = "D:/test/ssd/mobilenet-ssd/MobileNetSSD_deploy.caffemodel";
int main(int argc, char **argv)
{
VideoCapture capture;
capture.open("D:/test/dog.avi");
if (!capture.isOpened())
{
cout << "视频文件未找到!!!" << endl;
return -1;
}
Mat frame;
vector<string>objnames=labels();
Net net;
net = readNetFromCaffe(deploy_file, model_file);//读取二进制文件和描述文件
Mat inputblob,detection;
while (capture.read(frame))
{
imshow("input video", frame);
inputblob = blobFromImage(frame, 0.007843f, Size(width , height), 127.5, false, false);
//0.007843f是开发作者文档中唯一确定的,就是这个参数
net.setInput(inputblob, "data");
detection =net.forward("detection_out");
Mat detectionMat(detection.size[2], detection.size[3],CV_32F, detection.ptr<float>());
float confidence_threshold = 0.3;
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at<float>(i, 2);
if (confidence > confidence_threshold)
{
size_t objnameIndex = (size_t)detectionMat.at<float>(i, 1);
float tl_x = detectionMat.at<float>(i, 3) * frame.cols;
float tl_y = detectionMat.at<float>(i, 4) * frame.rows;
float br_x = detectionMat.at<float>(i, 5) * frame.cols;
float br_y = detectionMat.at<float>(i, 6) * frame.rows;
Rect objrect((int)tl_x,(int)tl_y,int(br_x-tl_x),int(br_y-tl_y));
rectangle(frame, objrect, Scalar(0, 0, 255), 2, 8, 0);
putText(frame,objnames[objnameIndex], Point(tl_x, tl_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
}
}
imshow("output video",frame);
char c = waitKey(20);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
destroyAllWindows();
return 0;
}
vector<String> labels()
{
vector<String>objNames;
ifstream fp(label_file);//打开输入流,读入文件
if (!fp.is_open())
{
printf("文件读入失败!!!\n");
exit(-1);//直接退出
}
string name;//标签文件中都有对应的名字
while (!fp.eof())//当文件没有读到结尾
{
getline(fp, name);//读取每一行
if (name.length())
{
string temp1 = name.substr(name.find(",") + 1); //找到每行第一个逗号,从逗号后面开始取数据
string temp2 = temp1.substr(temp1.find(",") + 1);//找到新的(第二个)逗号,从逗号后面开始取数据
objNames.push_back(temp2);
}
}
/*for (vector<string>::iterator iter = objNames.begin(); iter != objNames.end(); ++iter)
{
//输出*iter才是输出那些字符串
cout << *iter << endl;
}*/
return objNames;
}
运行结果: