FCN Caffe:可视化featureMaps和Weights(C++)、获取FCN结果
为何不使用C++版本FCN获取最后的分割掩模像素块集合,何必要使用python呢!因此需要获取网络最后层的所有featureMaps,featureMaps的结果直接对应了segmentation的最终结果,可以直接用于掩模分析。
caffe源码给出了提取中间层featureMap的源代码,位置在tools/extract_features.cpp。 参考文章链接: caffe模型可视化featureMaps和Weights(C++) ,文章有大量修改,如有不适,请移步原文。FCN:Fully Convolutional Networks。
1. 可视化最后一层featureMap的代码段(稍作修改):
int Classifier::visualize_featuremap( const cv::Mat& img, string layer_name, std::vector<cv::Mat> &Maps )
{Maps.resize(0);Blob<float>* input_layer = net_->input_blobs()[0];input_layer->Reshape(1, num_channels_, input_geometry_.height, input_geometry_.width);net_->Reshape();std::vector<cv::Mat> input_channels;WrapInputLayer(&input_channels);Preprocess(img, &input_channels);net_->Forward();std::cout << "网络中的Blobs名称为:\n";vector<shared_ptr<Blob<float> > > blobs = net_->blobs();vector<string> blob_names = net_->blob_names();std::cout << blobs.size() << " " << blob_names.size() << std::endl;for (int i = 0; i < blobs.size(); i++){std::cout << blob_names[i] << " " << blobs[i]->shape_string() << std::endl;}std::cout << std::endl;assert(net_->has_blob(layer_name));shared_ptr<Blob<float> > conv1Blob = net_->blob_by_name(layer_name);std::cout << "测试图片的特征响应图的形状信息为:" << conv1Blob->shape_string() << std::endl;float maxValue = -10000000, minValue = 10000000;const float* tmpValue = conv1Blob->cpu_data();for (int i = 0; i < conv1Blob->count(); i++){maxValue = std::max(maxValue, tmpValue[i]);minValue = std::min(minValue, tmpValue[i]);}int width = conv1Blob->shape(3); //响应图的高度 int height = conv1Blob->shape(2); //响应图的宽度 int channel = conv1Blob->shape(1); //通道数 int num = conv1Blob->shape(0); //个数 int imgHeight = (int)(1 + sqrt(channel))*height;int imgWidth = (int)(1 + sqrt(channel))*width;cv::Mat img(imgHeight, imgWidth, CV_8UC1, cv::Scalar(0));int kk = 0;for (int x = 0; x < imgHeight; x += height){for (int y = 0; y < imgWidth; y += width){if (kk >= channel)continue;cv::Mat roi(height, width, CV_8UC1);//cv::Mat roi = img(cv::Rect(y, x, width, height));for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){float value = conv1Blob->data_at(0, kk, i, j);//速度稍慢,应该有快速复制方法//roi.at<uchar>(i, j) = (value - minValue) / (maxValue - minValue) * 255;value = (value - minValue) / (maxValue - minValue);roi.at<uchar>(i, j) = 255* floor(value / 0.5) ;}}Maps.push_back(roi);kk++;}}return Maps.size();
}
2. 获取FCN的最终输出
vector<Blob<float>* > outBlob = net_->Forward();//得到的结果仍为151个//输出结果为151个模板int channel = outBlob[0]->shape(1);int hi = outBlob[0]->shape(2);int wi = outBlob[0]->shape(3);int area = wi*hi;vector<shared_ptr<Blob<float> > > blobs = net_->blobs();vector<string> blob_names = net_->blob_names();
获取最大标记
int Classifier::GetMaxMask( const cv::Mat& img, int layerIdx, double thres,cv::Mat &maskMax )
{vector<boost::shared_ptr<Blob<float> > > blobs = net_->blobs();vector<string> blob_names = net_->blob_names();int num_features = net_->output_blobs()[0]->shape(1);int channel = net_->output_blobs()[0]->shape(1);int hi = net_->output_blobs()[0]->shape(2);int wi = net_->output_blobs()[0]->shape(3);int area = wi*hi;std::vector<int> image_indices(num_features, 0);int i = layerIdx;const boost::shared_ptr<Blob<float> > feature_blob= net_->blob_by_name(blob_names[i]);int batch_size = feature_blob->num();int dim_features = feature_blob->count() / batch_size;float maxValue = -10000000, minValue = 10000000;const float* tmpValue = feature_blob->cpu_data();for (int i = 0; i < feature_blob->count(); i++){maxValue = std::max(maxValue, tmpValue[i]);minValue = std::min(minValue, tmpValue[i]);}std::vector<int> areal(channel);for (int i = 0; i < channel;++i){areal[i] = i*area;}const float* feature_blob_data;const float minv = 10000000;const float maxv = -10000000;int classI = 0;for ( int n = 0; n < batch_size; ++n){feature_blob_data =feature_blob->cpu_data() + feature_blob->offset(n);int img_index = 0;for (int h = 0; h < hi; ++h){uchar* ptr = (unsigned char*)(maskMax.data + h * maskMax.step);int idxH = h*wi;img_index = idxH;for ( int w = 0; w < wi; ++w){float valueG = maxv;for ( int c = 0; c < channel; ++c){int datum_index = areal[c] + img_index;// area*c;float value = static_cast<float>(feature_blob_data[datum_index]);if ( valueG < value ){valueG = value;classI = c;}}*ptr = (uchar)classI;++ptr;++img_index;}}} return 1;
}
获取所有标记
//获取特定的元,使用点数限制
int Classifier::getAllSeg(cv::Mat &im_inp, cv::Mat &maskMax, std::vector<cv::Mat > &segs,std::vector<std::pair<int,float> > &labels, const int nPointMin)
{std::vector<int> numsc(m_nClass);int h = maskMax.rows;int w = maskMax.cols;for (int i = 0; i < maskMax.rows; ++i){uchar *ptrm = maskMax.ptr<uchar>(i);for (int j = 0; j < maskMax.cols; ++j){int c = *ptrm;numsc[c]++;++ptrm;}}//添加限制,获取分割图std::map<int, int> maps;int k = 0;for (int i = 0; i < numsc.size();++i){if (numsc[i]>nPointMin){auto idx =make_pair(i,1.0f);labels.push_back(idx);auto idxm = make_pair(i, k);maps.insert(idxm);++k;}}//获取图像for (int i = 0; i < labels.size(); ++i){cv::Mat seg(h, w, CV_8UC3);segs.push_back(seg);}std::vector<uchar *> ptres(labels.size());for (int idx = 0; idx < labels.size(); ++idx){ptres[idx] = (uchar *)segs[idx].data;}for ( int i = 0; i < maskMax.rows; ++i ){uchar *ptr = im_inp.ptr<uchar>(i);uchar *ptrm = maskMax.ptr<uchar>(i);for (int n = 0; n < labels.size(); ++n) ptres[n] = (uchar *)segs[n].ptr<uchar>(i);for ( int j = 0; j < maskMax.cols; ++j ){int c = *ptrm;int pos;// = maps[c];auto l_it = maps.find(c);if ( l_it == maps.end() )pos = -1;else pos = l_it->second;if ( pos>-1) *(ptres[pos]) = *ptr;++ptr;for (int n = 0; n < labels.size();++n) ++ptres[n];if (pos>-1) *(ptres[pos]) = *ptr;++ptr;for (int n = 0; n < labels.size(); ++n) ++ptres[n];if (pos>-1) *(ptres[pos]) = *ptr;++ptr;for (int n = 0; n < labels.size(); ++n) ++ptres[n];++ptrm;}}int nseg = segs.size();return nseg;
}
3.此外,可视化权值的代码段,直接摘抄
cv::Mat visualize_weights(string prototxt, string caffemodel, int weights_layer_num) { ::google::InitGoogleLogging("0"); #ifdef CPU_ONLY Caffe::set_mode(Caffe::CPU); #else Caffe::set_mode(Caffe::GPU); #endif Net<float> net(prototxt, TEST); net.CopyTrainedLayersFrom(caffemodel); vector<shared_ptr<Blob<float> > > params = net.params(); std::cout << "各层参数的维度信息为:\n"; for (int i = 0; i<params.size(); ++i) std::cout << params[i]->shape_string() << std::endl; int width = params[weights_layer_num]->shape(3); //宽度 int height = params[weights_layer_num]->shape(2); //高度 int channel = params[weights_layer_num]->shape(1); //通道数 int num = params[weights_layer_num]->shape(0); //个数 int imgHeight = (int)(1 + sqrt(num))*height; int imgWidth = (int)(1 + sqrt(num))*width; Mat img(imgHeight, imgWidth, CV_8UC3, Scalar(0, 0, 0)); float maxValue = -1000, minValue = 10000; const float* tmpValue = params[weights_layer_num]->cpu_data(); for (int i = 0; i<params[weights_layer_num]->count(); i++){ maxValue = std::max(maxValue, tmpValue[i]); minValue = std::min(minValue, tmpValue[i]); } int kk = 0; for (int y = 0; y<imgHeight; y += height){ for (int x = 0; x<imgWidth; x += width){ if (kk >= num) continue; Mat roi = img(Rect(x, y, width, height)); for (int i = 0; i<height; i++){ for (int j = 0; j<width; j++){ for (int k = 0; k<channel; k++){ float value = params[weights_layer_num]->data_at(kk, k, i, j); roi.at<Vec3b>(i, j)[k] = (value - minValue) / (maxValue - minValue) * 255; } } } ++kk; } } return img; }
3.FeatureMap获取结果
原图:
分割结果显示:
参考:经典论文 Fully Convolutional Networks for semantic Segmentation
核心观点是建立“全卷积”网络,输入任意尺寸,经过有效的推理和学习产生相应尺寸的输出。定义并指定全卷积网络的空间,解释它们在空间范围内dense prediction任务(预测每个像素所属的类别)和获取与先验模型联系的应用。
---------------------------
通常CNN网络在卷积层之后会接上若干个全连接层, 将卷积层产生的特征图(feature map)映射成一个固定长度的特征向量。以AlexNet为代表的经典CNN结构适合于图像级的分类和回归任务,因为它们最后都期望得到整个输入图像的一个数值描述(概率),比如AlexNet的ImageNet模型输出一个1000维的向量表示输入图像属于每一类的概率(softmax归一化)。
FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。
最后逐个像素计算softmax分类的损失, 相当于每一个像素对应一个训练样本。
网络结构:
作者又翻译了一遍
FCN因受基础网络结构的不同影响,与不同基础网络结合的结果如下:
在分割任务上,网络结构相对过拟合的GoogleLeNet效果不能超过标准结构AlexNet。
总结:
pooling层的多层分布,最终用于预测每个点的类别信息,pooling层的粒度与最终分割的精度产生关联。
FCN Caffe:可视化featureMaps和Weights(C++)、获取FCN结果相关推荐
- fcn+caffe+siftflow实验记录
环境搭建: vs2013,编译caffe工程,cuda8.0,cudnn5.1,python2.7. 还需要安装python的一些包.Numpy+mkl scipy matplotlib sci ...
- Django博客来访人员地域分布大数据可视化---echarts绘图、geoip2获取地理位置
文章目录 Django博客来访人员地域分布大数据可视化---echarts绘图.geoip2获取地理位置 效果 echarts作图 geoip2获取地理位置 api接口开发 ajax前后端动态交互 D ...
- YOLOv5的Tricks | 【Trick11】在线模型训练可视化工具wandb(Weights Biases)
如有错误,恳请指出. 与其说是yolov5的训练技巧,这篇博客更多的记录如何使用wandb这个在线模型训练可视化工具,感受到了yolov5作者对其的充分喜爱. 所以下面内容更多的记录下如何最简单的使用 ...
- 【大数据】城市公交网络分析与可视化(三):获取公交站点信息并可视化站点重要程度
博客内容简介 通过前面的探究,我们大体知道如何获取一个城市的公交数据,并绘制了公交行驶路径散点图(效果不是很理想). 其实散点图感觉更适合类似于绘制公交站点这样的信息(行驶轨迹有其他更好的绘制技巧), ...
- windows平台下caffe可视化配置
平台环境 windows8.1,visual studio 2013 ,Anaconda2(本文安装路径为C:\Anaconda2),暂时无GPU支持 步骤 1.编译pycaffe 从https:// ...
- 【大数据】城市公交网络分析与可视化(五):获取公交平均路线长度、站点数、站距
内容简介 也不前情提要了,本博客内容高度概括就是:通过直接遍历法和依据文本法获取一个城市的"所有"线路名,并计算这些线路的平均路线长度.平均站点数.平均站距("直线系数& ...
- 图像语义分割入门:FCN/U-Net网络解析
向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程 公众号:datayx 图像语义分割(Semantic Segmentation)是图像处理和是机器视觉技术中关于图像 ...
- FCN制作自己的数据集、训练和测试 caffe
原文:http://blog.csdn.net/zoro_lov3/article/details/74550735 FCN制作自己的数据集.训练和测试全流程 花了两三周的时间,在导师的催促下,把FC ...
- caffe 提取特征并可视化(已测试可执行)及在线可视化
网络结构在线可视化工具 http://ethereon.github.io/netscope/#/editor 参考主页: caffe 可视化的资料可在百度云盘下载 链接: http://pan.ba ...
最新文章
- NLP | 医学AI又一突破,微软开源生物医学NLP基准:BLURB
- 如何用C#语言构造蜘蛛程序
- CentOs7中resourcemanager启动不了
- CMD命令操作MySql数据库详解
- 行转列(FOR XML PATH)
- SOAP 及其安全控制--转载
- Drools 在告警关联分析中的应用
- 为什么不懂技术的人可以做产品经理?
- 命令行上的narrowing(随着输入逐步减少备选项)工具
- 重量计算python月球_千年前的古诗,苏轼的不知月亮上是何年何月|现在我用Python来计算出来了...
- php 建站要学,建站新手如何开始学习php?
- 提前祝各位:圣诞节快乐~
- 神策分析 iOS SDK 架构解析
- 孩子学python_教孩子学编程 Python
- 类编程的WAF(下)
- 基于C++的简易的国际象棋双人对战程序设计
- W dBm功率换算公式
- JSCORE03(达)
- linux根据文件名批量下载,Linux下多文件按照指定顺序批量解压和按照指定文件名更名...
- 【小沐学NLP】Python实现聊天机器人(ELIZA)
热门文章
- Robot Framework(十七) 扩展RobotFramework框架——扩展Robot Framework Jar
- python3 与 Django 连接数据库:Error loading MySQLdb module: No module named 'MySQLdb'
- 《C++游戏编程入门(第4版)》——1.11 问题讨论
- objective-c 逐帧动画
- pthread_t描述说明
- iphone网络交互json实现
- mysql基础命令大全
- [MFC]设置文件夹目录时遇到的问题
- 36/100. Generate Parentheses
- Centos7 WARNING: ‘aclocal-1.15‘ is missing on your system.