//============================================================================= vector<Point2f> patch_models:: apply_simil(const Mat &S, const vector<Point2f> &points) { int n = points.size(); vector<Point2f> p(n); for(int i = 0; i < n; i++){ p[i].x = S.fl(0,0)*points[i].x + S.fl(0,1)*points[i].y + S.fl(0,2); p[i].y = S.fl(1,0)*points[i].x + S.fl(1,1)*points[i].y + S.fl(1,2); }return p; }
//============================================================================== bool face_detector:: enough_bounded_points(const Mat &pts, const Rect R, const float frac) { int n = pts.rows/2,m = 0; for(int i = 0; i < n; i++){ if((pts.fl(2*i ) >= R.x) && (pts.fl(2*i ) <= R.x + R.width) && (pts.fl(2*i+1) >= R.y) && (pts.fl(2*i+1) <= R.y + R.height))m++; } if(float(m)/n >= frac)return true; else return false; }
//============================================================================== Mat shape_model:: center_shape(const Mat &pts) { int n = pts.rows/2; float mx = 0,my = 0; for(int i = 0; i < n; i++){ mx += pts.fl(2*i); my += pts.fl(2*i+1); } Mat p(2*n,1,CV_32F); mx /= n; my /= n; for(int i = 0; i < n; i++){ p.fl(2*i) = pts.fl(2*i) - mx; p.fl(2*i+1) = pts.fl(2*i+1) - my; }return p; }
//============================================================================== void shape_model:: train(const vector<vector<Point2f> > &points, const vector<Vec2i> &con, const float frac, const int kmax) { //vectorize points // 把N张图片中的n个点的坐标排成一个N*2n的矩阵 Mat X = this->pts2mat(points); int N = X.cols,n = X.rows/2; //align shapes // 把这些shape先用procustes方法对齐 Y = this->procrustes(X); //compute rigid transformation Mat R = this->calc_rigid_basis(Y); //compute non-rigid transformation Mat P = R.t()*Y; Mat dY = Y - R*P; 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;}} 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); Mat Vd = V(Rect(4,0,k,2*n)); D.copyTo(Vd); //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); for(int i = 0; i < 4+k; i++){ if(i < 4)e.fl(i) = -1; 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; } }
//============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== void patch_models:: train(ft_data &data, const vector<Point2f> &ref, const Size psize, const Size ssize, const bool mirror, const float var, const float lambda, const float mu_init, const int nsamples, const bool visi) { //set reference shape int n = ref.size(); reference = Mat(ref).reshape(1,2*n); Size wsize = psize + ssize; //train each patch model in turn patches.resize(n); for(int i = 0; i < n; i++){ if(visi)cout << "training patch " << i << "..." << endl; vector<Mat> images(0); for(int j = 0; j < data.n_images(); j++){ Mat im = data.get_image(j,0); // imshow("im",im); vector<Point2f> p = data.get_points(j,false); Mat pt = Mat(p).reshape(1,2*n); Mat S = this->calc_simil(pt),A(2,3,CV_32F); A.fl(0,0) = S.fl(0,0); A.fl(0,1) = S.fl(0,1); A.fl(1,0) = S.fl(1,0); A.fl(1,1) = S.fl(1,1); A.fl(0,2) = pt.fl(2*i ) - (A.fl(0,0) * (wsize.width-1)/2 + A.fl(0,1)*(wsize.height-1)/2); A.fl(1,2) = pt.fl(2*i+1) - (A.fl(1,0) * (wsize.width-1)/2 + A.fl(1,1)*(wsize.height-1)/2); Mat I; warpAffine(im,I,A,wsize,INTER_LINEAR+WARP_INVERSE_MAP); images.push_back(I); if(mirror){ im = data.get_image(j,1); p = data.get_points(j,true); pt = Mat(p).reshape(1,2*n); S = this->calc_simil(pt); A.fl(0,0) = S.fl(0,0); A.fl(0,1) = S.fl(0,1); A.fl(1,0) = S.fl(1,0); A.fl(1,1) = S.fl(1,1); A.fl(0,2) = pt.fl(2*i ) - (A.fl(0,0) * (wsize.width-1)/2 + A.fl(0,1)*(wsize.height-1)/2); A.fl(1,2) = pt.fl(2*i+1) - (A.fl(1,0) * (wsize.width-1)/2 + A.fl(1,1)*(wsize.height-1)/2); warpAffine(im,I,A,wsize,INTER_LINEAR+WARP_INVERSE_MAP); images.push_back(I); } } patches[i].train(images,psize,var,lambda,mu_init,nsamples,visi); } }
//============================================================================== float face_detector:: calc_scale(const Mat &pts) { Point2f c = this->center_of_mass(pts); int n = pts.rows/2; Mat p(2*n,1,CV_32F); for(int i = 0; i < n; i++){ p.fl(2*i ) = pts.fl(2*i ) - c.x; p.fl(2*i+1) = pts.fl(2*i+1) - c.y; }return reference.dot(p)/reference.dot(reference); }
//============================================================================= Mat shape_model:: rot_scale_align(const Mat &src, const Mat &dst) { //construct linear system int n = src.rows/2; float a=0,b=0,d=0; for(int i = 0; i < n; i++){ d += src.fl(2*i) * src.fl(2*i ) + src.fl(2*i+1) * src.fl(2*i+1); a += src.fl(2*i) * dst.fl(2*i ) + src.fl(2*i+1) * dst.fl(2*i+1); b += src.fl(2*i) * dst.fl(2*i+1) - src.fl(2*i+1) * dst.fl(2*i ); } a /= d; b /= d;//solved linear system return (Mat_<float>(2,2) << a,-b,b,a); }
//============================================================================= Mat patch_models:: inv_simil(const Mat &S) { Mat Si(2,3,CV_32F); float d = S.fl(0,0)*S.fl(1,1) - S.fl(1,0)*S.fl(0,1); Si.fl(0,0) = S.fl(1,1)/d; Si.fl(0,1) = -S.fl(0,1)/d; Si.fl(1,1) = S.fl(0,0)/d; Si.fl(1,0) = -S.fl(1,0)/d; Mat Ri = Si(Rect(0,0,2,2)); Mat t = -Ri*S.col(2),St = Si.col(2); t.copyTo(St); return Si; }
//============================================================================== void shape_model:: calc_params(const vector<Point2f> &pts,const Mat weight,const float c_factor) { int n = pts.size(); assert(V.rows == 2*n); Mat s = Mat(pts).reshape(1,2*n); //point set to vector format if(weight.empty())p = V.t()*s; //simple projection else{ //scaled projection if(weight.rows != n){cout << "Invalid weighting matrix" << endl; abort();} int K = V.cols; Mat H = Mat::zeros(K,K,CV_32F),g = Mat::zeros(K,1,CV_32F); for(int i = 0; i < n; i++){ Mat v = V(Rect(0,2*i,K,2)); float w = weight.fl(i); H += w*v.t()*v; g += w*v.t()*Mat(pts[i]); } solve(H,g,p,DECOMP_SVD); }this->clamp(c_factor); //clamp resulting parameters }