Caffe-Face extractDeepFeature C++

Caffe-Face 特征提取C++版本


说明:

根据extractDeepFeature.m修改的C++版本

extractDeepFeature.cpp:

#include <string>
#include <vector>
#include <fstream>
#include <caffe/caffe.hpp>
#include <caffe/layers/memory_data_layer.hpp>
#include <opencv2/opencv.hpp>
#include "boost/make_shared.hpp"

#define NetF float  
#define USING_GPU //使用GPU

#define IMAGE_WIDTH_STD 96//裁剪的图片大小
#define IMAGE_HEIGHT_STD 112

#define LANDMARK_SIZE 5//对齐点的个数
#define LANDMARK_SIZE_DOUBLE 10//对齐点个数的两倍

using namespace caffe;
using namespace std;
using namespace cv;

double src_landmark[LANDMARK_SIZE_DOUBLE] = {
    105.8306, 147.9323, 121.3533, 106.1169, 144.3622,
    109.8005, 112.5533, 139.1172, 155.6359, 156.3451 };
double dst_landmark[LANDMARK_SIZE_DOUBLE] = {
    30.2946, 65.5318, 48.0252, 33.5493, 62.7299,
    51.6963, 51.5014, 71.7366, 92.3655, 92.2041 };

template <typename Dtype>
caffe::Net<Dtype>* Net_Init_Load(
    std::string param_file, std::string pretrained_param_file, caffe::Phase phase)
{
    caffe::Net<Dtype>* net(new caffe::Net<Dtype>(param_file, phase));
    net->CopyTrainedLayersFrom(pretrained_param_file);
    return net;
}

int main(int argc,char **argv)
{
    ::google::InitGoogleLogging(argv[0]);
#ifdef USING_GPU
    Caffe::set_mode(Caffe::GPU);
#else
    Caffe::set_mode(Caffe::CPU);
#endif   
    //加载配置和模型文件
    caffe::Net<NetF>* _net = Net_Init_Load<NetF>("../model/face_deploy.prototxt", 
                                                "../model/face_model.caffemodel", caffe::TEST);  
    vector<Point2f> facial5points;
    vector<Point2f> coord5points;
    for (int i = 0; i < LANDMARK_SIZE; i++)
    {
        facial5points.push_back(Point2f(src_landmark[i], src_landmark[i + LANDMARK_SIZE]));
        coord5points.push_back(Point2f(dst_landmark[i], dst_landmark[i + LANDMARK_SIZE]));
    }

    Mat image, warp_mat, cropImg, cropImg_;
    image = imread("../data/1.jpg",1);
    imshow("frame", image);//显示原图片

    warp_mat = estimateRigidTransform(facial5points, coord5points, false);
    if (warp_mat.empty())
    {
        std::cout << "NULL" << std::endl;
        return 0;
    }

    cropImg = Mat::zeros(IMAGE_HEIGHT_STD, IMAGE_WIDTH_STD, image.type());
    warpAffine(image, cropImg, warp_mat, cropImg.size());//裁剪图片

    cropImg.convertTo(cropImg, CV_32F);
    cropImg = (cropImg - 127.5) / 128;//均值归一化图片
    imshow("normalization", cropImg);
    /*
    transpose(cropImg, cropImg);//转置图片(matlab与C++图片存储方式不同不需要转置)

    Mat temp;//matlab与C++彩色三通道的顺序不同,matlab为RGB,C++为BGR。matlab中需要在提特征时调整顺序,C++则不需要。
    vector<Mat> channels;
    split(cropImg, channels); //通道的拆分   
    temp = channels.at(0);
    channels.at(0) = channels.at(2);
    channels.at(2) = temp;
    merge(channels, cropImg);//拆分通道的合并  
    imshow("cropImg", cropImg);
    */

    flip(cropImg, cropImg_, 0);
    imshow("cropImg_", cropImg_);//镜像翻转

    cropImg.convertTo(cropImg, CV_8U); //这个地方可以考虑使用Datum类型来传递float类型的图片
    cropImg_.convertTo(cropImg_, CV_8U); 

    std::vector<cv::Mat> dv = { cropImg,cropImg_ };//对齐后图片,这里为两张图片需要修改face_deploy.prototxt中data层batch_size:2
    std::vector<int> label = { 0,0 };//图片标签(可随便写)

    caffe::MemoryDataLayer<NetF> *m_layer_ = (caffe::MemoryDataLayer<NetF> *)_net->layers()[0].get();//定义数据层指针
    m_layer_->AddMatVector(dv, label);//将图片和标签添加到MemoryData层

    int end_ind = _net->layers().size();
    std::vector<caffe::Blob<NetF>*> input_vec;

    clock_t start = clock();
    _net->Forward(input_vec);//提特征
    clock_t end = clock();
    double totaltime;
    totaltime = (double)(end - start) / CLOCKS_PER_SEC;

    boost::shared_ptr<caffe::Blob<NetF>> fc5 = _net->blob_by_name("fc5");
    const NetF* pstart = fc5->cpu_data();//*pstart只代表数组的第一个数

    std::vector<double> V1;
    for (int i = 0; i < 1024; i++)//循环获取特征数据,1张图片特征为512个
    {
        std::cout << *pstart << endl;
        V1.push_back(*pstart);
        pstart++;
    }
    cout << "\n此程序的运行时间为" << totaltime << "秒!" << endl;
    cvWaitKey(0);
    return 0;
}

配置文件数据层:

layer{
  name: "data"
  type: "MemoryData"
  top: "data"
  top: "label"
  memory_data_param{
    batch_size:2
    channels:3
    height:112
    width:96
  }
}

参考:http://blog.csdn.net/sunshine_in_moon/article/details/50126307
Demo:点击下载

代码更新:

//mat转Datum类型
bool CvMatToDatumSignalChannel(const cv::Mat& cv_mat, Datum* datum){
  if (cv_mat.empty())
    return false;
  int channels = cv_mat.channels();

  datum->set_channels(cv_mat.channels());
  datum->set_height(cv_mat.rows);
  datum->set_width(cv_mat.cols);
  datum->set_label(0);
  datum->clear_data();
  datum->clear_float_data();
  datum->set_encoded(false);

  int datum_height = datum->height();
  int datum_width  = datum->width();
  if(channels == 3){
    for(int c = 0;c < channels;c++){
      for (int h = 0; h < datum_height; ++h){
        for (int w = 0; w < datum_width; ++w){
          const float* ptr = cv_mat.ptr<float>(h);
          datum->add_float_data(ptr[w*channels+c]);
        }
      }
    }
  }

  return true;
}

//提特征
Mat getFeature(Mat image,vector<Point2f> points){
    Mat warp_mat, cropImg, cropImg_;

    cropImg = matlabtransform(image,points);//crop图片,可使用其他方法。

    cropImg.convertTo(cropImg, CV_32FC3);
    cropImg = (cropImg - 127.5) / 128;//均值归一化图片

    flip(cropImg, cropImg_, 1);//镜像翻转

    boost::shared_ptr<MemoryDataLayer<float> > mem_data_layer;
    mem_data_layer = boost::static_pointer_cast<MemoryDataLayer<float> >(_net->layers()[0]);
    Datum datum,datum_;
    CvMatToDatumSignalChannel(cropImg,&datum);  
    CvMatToDatumSignalChannel(cropImg_,&datum_);

    std::vector<Datum> datum_vector;
    datum_vector.push_back(datum); 
    datum_vector.push_back(datum_); 
    mem_data_layer->set_batch_size(2);
    mem_data_layer->AddDatumVector(datum_vector);

    _net->Forward();

    boost::shared_ptr<caffe::Blob<NetF> > fc5 = _net->blob_by_name("fc5");
    const NetF* pstart = fc5->cpu_data();//*pstart只代表数组的第一个数

    cv::Mat tmp(1024, 1, CV_32FC1);//获取特征值
    for(int i=0;i<1024;i++){
        for(int j=0;j<1;j++){
            tmp.at<float>(i,j) = (float)*pstart;
            pstart++;       
        }   
    }

    return tmp;
}

mTransform.m

function [R,G,B] = mTransform(B_image,G_image,R_image,facial5points)
image(:,:,1) = R_image;
image(:,:,2) = G_image;
image(:,:,3) = B_image;
image = permute(image, [2,1,3]);

imgSize = [112, 96];
coord5points = [30.2946, 65.5318, 48.0252, 33.5493, 62.7299; ...
        51.6963, 51.5014, 71.7366, 92.3655, 92.2041];

Tfm = cp2tform(facial5points', coord5points', 'similarity');
cropImg = imtransform(image, Tfm, 'XData', [1 imgSize(2)],...
        'YData', [1 imgSize(1)], 'Size', imgSize);

R = cropImg(:,:,1);
G = cropImg(:,:,2);
B = cropImg(:,:,3);
end
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sun-Eve

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值