#include <iostream>
#include <unistd.h>
#include <opencv4/opencv2/opencv.hpp>//理论上opencv3.3.*和3.4.*也可以,未测试
#include <opencv4/opencv2/dnn.hpp>
#include <opencv4/opencv2/dnn/dnn.hpp>
using namespace std;

std::string strip(const std::string& str,const std::string& del){
    std::string res = str;
    size_t pos=res.find_first_of(del);
    size_t len=del.length();
    while(pos!=std::string::npos){
        res.erase(res.begin()+pos,res.begin()+pos+len);
        pos=res.find_first_of(del);
    }
    return res;
}
int main(int argc, char *argv[]) { //建议 OPENCV 4.*.* cerr<<"WORKING IN OPENCV_VERSION "<<CV_VERSION<<'\n'; cv::Mat src = cv::imread("src.jpg");
//加载模型所用的网络结构文件和参数文件,这里用的是caffe训练得到的MobileNet-SSD
string cfg ="MobileNetSSD_deploy.prototxt"; string weights ="mobilenet_iter_25000.caffemodel"; cv::dnn::Net net = cv::dnn::readNetFromCaffe(cfg,weights); if(net.empty()){ cerr<<"loaded net failed.\n"; return -1; }
//图片输入到输入层 cv::Mat inputBlob
= cv::dnn::blobFromImage(src, 1/255.F, cv::Size(300, 300), cv::Scalar(), false, false); net.setInput(inputBlob,"data");
//遍历一遍网络结构,查看各层的变化(暂未输出各层的连接关系) vector
<cv::String> outputname=net.getLayerNames(); cv::dnn::MatShape netInputSize = {1,3,300,300}; vector<cv::dnn::MatShape> netlastSize; vector<vector<cv::dnn::MatShape> >layerSizes; for(size_t i=0;i<outputname.size();++i){ vector<cv::dnn::MatShape>inputLayerSize; vector<cv::dnn::MatShape>outputLayerSize; net.getLayerShapes(netInputSize,i,inputLayerSize,outputLayerSize); cerr<<"layer <<"<<outputname[i]<<">> size [\n"; for(size_t j=0;j<inputLayerSize.size();++j){ cerr<<"\t["<<inputLayerSize[j][0];for(size_t k=1;k<inputLayerSize[j].size();++k)cerr<<" x "<<inputLayerSize[j][k];cerr<<"]\n"; } cerr<<"\tto\n"; for(size_t j=0;j<outputLayerSize.size();++j){ cerr<<"\t["<<outputLayerSize[j][0];for(size_t k=1;k<outputLayerSize[j].size();++k)cerr<<" x "<<outputLayerSize[j][k];cerr<<"]\n"; } cerr<<"]\n"; layerSizes.push_back(outputLayerSize); netlastSize=inputLayerSize; } //进行预测 vector<vector<cv::Mat> > outputBlob; try{ cerr<<"\nNet forward "; net.forward(outputBlob, outputname); cerr<<"done\n\n"; }catch(exception e){ cerr << e.what() << '\n'; }
//要保存的层的名字,具体名字可以在之前输出的信息里面找
string selectLayer="conv4"; for(size_t i=1;i<outputname.size();++i){ if(selectLayer!=outputname[i])continue; for(size_t j=0;j<outputBlob[i].size();++j){ try{ cv::Mat blob = outputBlob[i-1][j].clone(); cerr<<"blob dim = "<<blob.size.dims()<<" with type "<<blob.type()<<'\n'; //dim 4: b * c * w * h //dim 3: b * w * h //dim 2: b * w cv::Mat saveimg, temp; float* data=(float*)blob.data; string savepath; int s[2]={0};
//保存不同dim情况下的特征图
switch(blob.size.dims()){ case 2://单轴 saveimg.create(layerSizes[i][j][0],1,CV_8UC1); for(size_t pi=0; pi<layerSizes[i][j][0]; ++pi){ saveimg.data[pi]=data[pi]; } cv::normalize(saveimg,saveimg,255,0,cv::NORM_MINMAX); savepath = "layers/layer_"+strip(outputname[i],"/")+".jpg"; cv::imwrite(savepath,saveimg); saveimg.release(); break; case 3://单层卷积特征图 s[1]=layerSizes[i][j][1]; s[0]=layerSizes[i][j][2]; saveimg.create(layerSizes[i][j][1],layerSizes[i][j][2],CV_8UC1); for(size_t pi=0; pi<s[1]*s[0]; ++pi){ saveimg.data[pi]=(uchar)data[pi]; } cv::normalize(saveimg,saveimg,255,0,cv::NORM_MINMAX); savepath = "layers/layer_"+strip(outputname[i],"/")+".jpg"; cv::imwrite(savepath,saveimg); saveimg.release(); break; case 4://多层卷积特征图 for(int k=0;k<layerSizes[i][j][1];++k){ s[1]=layerSizes[i][j][2]; s[0]=layerSizes[i][j][3]; saveimg.create(layerSizes[i][j][2],layerSizes[i][j][3],CV_8UC1); for(size_t pi=0; pi<s[1]*s[0]; ++pi){ saveimg.data[pi]=(uchar)data[k*s[1]*s[0]+pi]; } cv::normalize(saveimg,saveimg,255,0,cv::NORM_MINMAX); savepath = "layers/layer_"+strip(outputname[i],"/")+"_channal_"+to_string(k)+".jpg"; cv::imwrite(savepath,saveimg); saveimg.release(); } break; default: cerr<<" exordinary dim\n"; break; } cerr<<"save to "<<savepath<<'\n'; blob.release(); }catch(exception e){ cerr<<" escape beacuse "<<e.what()<<'\n'; } } }
//检验数据类型的尺寸和序号 fprintf(stderr,
"float %d, double %d\n",sizeof(float),sizeof(double)); //blob <CV_32FC1,5> float fprintf(stderr, "type list : <CV_8UC1,%d> <CV_8UC3,%d> <CV_16FC1,%d> <CV_16FC3,%d> <CV_16SC1,%d> <CV_16SC3,%d> <CV_32FC1,%d> <CV_32SC1,%d> ", CV_8UC1,CV_8UC3,CV_16FC1,CV_16FC3,CV_16SC1,CV_16SC3,CV_32FC1,CV_32SC1); return 0; }

 

结果在运行目录下的layers文件夹中,这个文件夹要自己新建

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄