刚性人脸检测---形状模型

总的说来
形状空间是把任何一个人脸的特征点集分成刚性空间和非刚性空间,一共k+4列,该k+4列向量两两正交,然后使用投影的方法纠正对于识别的新图片的形状

刚性空间—- - 可以由运动和缩放构成的部分
下面经过计算可以得到4个正交的列向量来描述

非刚性空间—— 描述形变的部分,根据样本的个数使用PCA算法得到主要的k个列向量

下面先贴下总的训练代码

void
shape_model::
train(const vector<vector<Point2f> > &points,
      const vector<Vec2i> &con,
      const float frac,
      const int kmax)
{
  //vectorize points
  Mat X = this->pts2mat(points);
  int N = X.cols,n = X.rows/2;

  //align shapes
  Mat Y = this->procrustes(X);
  //compute rigid transformation, rigid subspace
  Mat R = this->calc_rigid_basis(Y);
  //compute non-rigid transformation
  Mat P = R.t()*Y; 
  Mat dY = Y - R*P; //project-out rigidity
  SVD svd(dY*dY.t());


  int m = min(min(kmax,N-1),n-1);
  float vsum = 0; for(int i = 0; i < m; i++)vsum += svd.w.fl(i);
  float v = 0; int k = 0; 
  for(k = 0; k < m; k++){v += svd.w.fl(k); if(v/vsum >= frac){k++; break;}}  /*取前k个奇异值*/
  if(k > m)k = m;
  Mat D = svd.u(Rect(0,0,k,2*n));

  //combine bases
  V.create(2*n,4+k,CV_32F);
  Mat Vr = V(Rect(0,0,4,2*n)); R.copyTo(Vr);//rigid subspace
  Mat Vd = V(Rect(4,0,k,2*n)); D.copyTo(Vd);//nonrigid subspace

  //compute variance (normalized wrt scale)
  Mat Q = V.t()*X;
  for(int i = 0; i < N; i++){
    float v = Q.fl(0,i); Mat q = Q.col(i); q /= v; 
  }
  e.create(4+k,1,CV_32F);
  pow(Q,2,Q); // multiply(Q,Q,Q);
  for(int i = 0; i < 4+k; i++){
    if(i < 4)e.fl(i) = -1;     //no clamping for rigid coefficients
    else e.fl(i) = Q.row(i).dot(Mat::ones(1,N,CV_32F))/(N-1); //点积
  }
  //store connectivity
  if(con.size() > 0){ //default connectivity
    int m = con.size();
    C.create(m,2,CV_32F);
    for(int i = 0; i < m; i++){
      C.at<int>(i,0) = con[i][0]; C.at<int>(i,1) = con[i][1];
    }
  }else{              //user-specified connectivity
    C.create(n,2,CV_32S);
    for(int i = 0; i < n-1; i++){
      C.at<int>(i,0) = i; C.at<int>(i,1) = i+1;
    }    
    C.at<int>(n-1,0) = n-1; C.at<int>(n-1,1) = 0;
  }
}

下面开始解释

Mat X = this->pts2mat(points);

这个函数做的事情是把所有的点都对其到零点坐标上
这里写图片描述

Mat Y = this->procrustes(X);

这个是进行procrustes分析,可以参考http://www.mamicode.com/info-detail-999642.html
这个只是procrustes分析的一种推广吧
个人也了解了下普通的procrustes分析,这里的procrustes分析只是思想上一致,方式取巧了

大致如下
这里写图片描述

 Mat R = this->calc_rigid_basis(Y);

这边是把数据进行矩阵化
R矩阵是将刚性空间施密特正交化的矩阵
关于施密特正交化的方式参照我的另一篇http://blog.csdn.net/limit_ing/article/details/62069691
这里写图片描述
这里写图片描述
显然前4列的列向量因为使用施密特正交法自然两两正交

  Mat P = R.t()*Y;
  Mat dY = Y - R*P; //project-out rigidity
  SVD svd(dY*dY.t());


  int m = min(min(kmax,N-1),n-1);
  float vsum = 0; for(int i = 0; i < m; i++)vsum += svd.w.fl(i);
  float v = 0; int k = 0; 
  for(k = 0; k < m; k++){v += svd.w.fl(k); if(v/vsum >= frac){k++; break;}}  /*取前k个奇异值*/
  if(k > m)k = m;
  Mat D = svd.u(Rect(0,0,k,2*n));

矩阵P是把样本点投影到刚性空间的成分
dY是样本点减去刚性空间的成分,就是非刚性部分
下面关于PCA参见我的http://blog.csdn.net/limit_ing/article/details/61970031
svd参见http://blog.csdn.net/limit_ing/article/details/62068466
上面两个包含个人推理过程,比较繁琐

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值