为何不使用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结果相关推荐

  1. fcn+caffe+siftflow实验记录

    环境搭建: vs2013,编译caffe工程,cuda8.0,cudnn5.1,python2.7. 还需要安装python的一些包.Numpy+mkl  scipy  matplotlib  sci ...

  2. Django博客来访人员地域分布大数据可视化---echarts绘图、geoip2获取地理位置

    文章目录 Django博客来访人员地域分布大数据可视化---echarts绘图.geoip2获取地理位置 效果 echarts作图 geoip2获取地理位置 api接口开发 ajax前后端动态交互 D ...

  3. YOLOv5的Tricks | 【Trick11】在线模型训练可视化工具wandb(Weights Biases)

    如有错误,恳请指出. 与其说是yolov5的训练技巧,这篇博客更多的记录如何使用wandb这个在线模型训练可视化工具,感受到了yolov5作者对其的充分喜爱. 所以下面内容更多的记录下如何最简单的使用 ...

  4. 【大数据】城市公交网络分析与可视化(三):获取公交站点信息并可视化站点重要程度

    博客内容简介 通过前面的探究,我们大体知道如何获取一个城市的公交数据,并绘制了公交行驶路径散点图(效果不是很理想). 其实散点图感觉更适合类似于绘制公交站点这样的信息(行驶轨迹有其他更好的绘制技巧), ...

  5. windows平台下caffe可视化配置

    平台环境 windows8.1,visual studio 2013 ,Anaconda2(本文安装路径为C:\Anaconda2),暂时无GPU支持 步骤 1.编译pycaffe 从https:// ...

  6. 【大数据】城市公交网络分析与可视化(五):获取公交平均路线长度、站点数、站距

    内容简介 也不前情提要了,本博客内容高度概括就是:通过直接遍历法和依据文本法获取一个城市的"所有"线路名,并计算这些线路的平均路线长度.平均站点数.平均站距("直线系数& ...

  7. 图像语义分割入门:FCN/U-Net网络解析

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 图像语义分割(Semantic Segmentation)是图像处理和是机器视觉技术中关于图像 ...

  8. FCN制作自己的数据集、训练和测试 caffe

    原文:http://blog.csdn.net/zoro_lov3/article/details/74550735 FCN制作自己的数据集.训练和测试全流程 花了两三周的时间,在导师的催促下,把FC ...

  9. caffe 提取特征并可视化(已测试可执行)及在线可视化

    网络结构在线可视化工具 http://ethereon.github.io/netscope/#/editor 参考主页: caffe 可视化的资料可在百度云盘下载 链接: http://pan.ba ...

最新文章

  1. NLP | 医学AI又一突破,微软开源生物医学NLP基准:BLURB
  2. 如何用C#语言构造蜘蛛程序
  3. CentOs7中resourcemanager启动不了
  4. CMD命令操作MySql数据库详解
  5. 行转列(FOR XML PATH)
  6. SOAP 及其安全控制--转载
  7. Drools 在告警关联分析中的应用
  8. 为什么不懂技术的人可以做产品经理?
  9. 命令行上的narrowing(随着输入逐步减少备选项)工具
  10. 重量计算python月球_千年前的古诗,苏轼的不知月亮上是何年何月|现在我用Python来计算出来了...
  11. php 建站要学,建站新手如何开始学习php?
  12. 提前祝各位:圣诞节快乐~
  13. 神策分析 iOS SDK 架构解析
  14. 孩子学python_教孩子学编程 Python
  15. 类编程的WAF(下)
  16. 基于C++的简易的国际象棋双人对战程序设计
  17. W dBm功率换算公式
  18. JSCORE03(达)
  19. linux根据文件名批量下载,Linux下多文件按照指定顺序批量解压和按照指定文件名更名...
  20. 【小沐学NLP】Python实现聊天机器人(ELIZA)

热门文章

  1. Robot Framework(十七) 扩展RobotFramework框架——扩展Robot Framework Jar
  2. python3 与 Django 连接数据库:Error loading MySQLdb module: No module named 'MySQLdb'
  3. 《C++游戏编程入门(第4版)》——1.11 问题讨论
  4. objective-c 逐帧动画
  5. pthread_t描述说明
  6. iphone网络交互json实现
  7. mysql基础命令大全
  8. [MFC]设置文件夹目录时遇到的问题
  9. 36/100. Generate Parentheses
  10. Centos7 WARNING: ‘aclocal-1.15‘ is missing on your system.