sai-bi / FaceAlignment

Face Alignment by Explicit Shape Regression
MIT License
339 stars 205 forks source link

SimilarityTransform, regress target #2

Open chenliangren opened 9 years ago

chenliangren commented 9 years ago
  1. what's the SimilarityTransform theory? I can't understand the SimilarityTransform function code. what i can refer to ?
  2. although i can understand the pixel is indexed realitve to mean shape, i want to know why the gradient,(i.e. regress target) must be transform to mean shape coordination like this: regression_targets[i] = scale * regression_targets[i] * rotation;
sai-bi commented 9 years ago
  1. If you can understand Chinese, please refer to this post. Otherwise, please refer to Appendix B of the book Statistical Models of Appearance for Computer Vision. You can access it here.
  2. Regression targets is the difference of ground truth shape and current shape. If you don't do alignment, this difference will mean nothing to testing, considering various size and orientations of face images.
chenliangren commented 9 years ago

thanks! the post link is not chinese, the same as "here",is it wrong? I'm still confused why the regress_target should be transfromed accroding to the mean shape.The paper only point out the index-shape feature should transfrom like this. 2.besides, I'm confused why the threshold should be seleced randomly. and in the code: "(-0.2_max_diff,0.2_max_diff)" what's the purpose of scaling the range by 0.2 factor ? i am wondering sorting the difference between two feature point and select the difference which best fit the data as threshold, does it work?

sai-bi commented 9 years ago
  1. @chenliangren Sorry the link is wrong, and I have updated it.
  2. Please refer to Chapter 4 of the book Statistical Models of Appearance for Computer Vision via the above link, especially the section Aligning the Training Set
  3. In fact, the threshold can be chosen in other ways, for example, choose the threshold to minimize the entropy and many other measures. You could try it.
windpls commented 8 years ago

@soundsilence Hi, I'm confused about the code of SimilarityTransform function. I have read your post and also the appendix of the materials your referred. But I don't understand your method calculating the "scale" in the code.

In the post, we need firstly get a and b, and then using s^2 = a^2 + b^2 to the final result. But you just calculated the covariance matrix and used the ratio of their L2-norm as the scale. Could you explain the underlying principle?

centosrhel commented 7 years ago

@windpls It's indeed quite confusing. The code snippet is inconsistent with Appendix B of the book

OsamaNabih commented 4 years ago

I have no idea what's going on with this function's code, but the output really doesn't make sense. I've tried implementing it as explained in Appendix B and it was simple and yielded a logical output that had lesser MSE than that produced by the current implementation. I suggest re-implementing this function.

sai-bi commented 4 years ago

Sorry that the code is very old and I am not even sure whether this is the version I use. Feel free to paste the correct code here and I would be happy to correct it. Thanks.

OsamaNabih commented 4 years ago

Here is my code, let me know if there's any adjustments to be made.

void SimilarityTransform(const Mat& shape1, const Mat& shape2, Mat_& rotation,double& scale){ rotation = Mat::zeros(2,2,CV_64FC1); scale = 0;

// center the data
double center_x_1 = 0;
double center_y_1 = 0;
double center_x_2 = 0;
double center_y_2 = 0;
for (int i = 0; i < shape1.rows; i++) {
    center_x_1 += shape1(i, 0);
    center_y_1 += shape1(i, 1);
    center_x_2 += shape2(i, 0);
    center_y_2 += shape2(i, 1);
}
center_x_1 /= shape1.rows;
center_y_1 /= shape1.rows;
center_x_2 /= shape2.rows;
center_y_2 /= shape2.rows;

Mat_<double> temp1 = shape1.clone();
Mat_<double> temp2 = shape2.clone();
for (int i = 0; i < shape1.rows; i++) {
    temp1(i, 0) -= center_x_1;
    temp1(i, 1) -= center_y_1;
    temp2(i, 0) -= center_x_2;
    temp2(i, 1) -= center_y_2;
}

double num_a = 0;
double num_b = 0;
double den = 0;

for (int i = 0; i < shape1.rows; i++) {
    num_a = num_a + temp1(i, 0) * temp2(i, 0) + temp1(i, 1) * temp2(i, 1);
    num_b = num_b + temp1(i, 0) * temp2(i, 1) - temp1(i, 1) * temp2(i, 0);
    den = den + temp1(i, 0) * temp1(i, 0) + temp1(i, 1) * temp1(i, 1);
}

double a = num_a / den;
double b = num_b / den;

double theta = atan(b / a);
double scale = sqrt(pow(a, 2) + pow(b, 2));
double cos_theta = cos(theta);
double sin_theta = sin(theta);
rotation(0,0) = cos_theta;
rotation(0,1) = -sin_theta;
rotation(1,0) = sin_theta;
rotation(1,1) = cos_theta;

}

OsamaNabih commented 4 years ago

Here is my code, let me know if there's any adjustments to be made.

void SimilarityTransform(const Mat& shape1, const Mat& shape2, Mat_& rotation,double& scale){ rotation = Mat::zeros(2,2,CV_64FC1); scale = 0;

// center the data
double center_x_1 = 0;
double center_y_1 = 0;
double center_x_2 = 0;
double center_y_2 = 0;
for (int i = 0; i < shape1.rows; i++) {
    center_x_1 += shape1(i, 0);
    center_y_1 += shape1(i, 1);
    center_x_2 += shape2(i, 0);
    center_y_2 += shape2(i, 1);
}
center_x_1 /= shape1.rows;
center_y_1 /= shape1.rows;
center_x_2 /= shape2.rows;
center_y_2 /= shape2.rows;

Mat_<double> temp1 = shape1.clone();
Mat_<double> temp2 = shape2.clone();
for (int i = 0; i < shape1.rows; i++) {
    temp1(i, 0) -= center_x_1;
    temp1(i, 1) -= center_y_1;
    temp2(i, 0) -= center_x_2;
    temp2(i, 1) -= center_y_2;
}

double num_a = 0;
double num_b = 0;
double den = 0;

for (int i = 0; i < shape1.rows; i++) {
    num_a = num_a + temp1(i, 0) * temp2(i, 0) + temp1(i, 1) * temp2(i, 1);
    num_b = num_b + temp1(i, 0) * temp2(i, 1) - temp1(i, 1) * temp2(i, 0);
    den = den + temp1(i, 0) * temp1(i, 0) + temp1(i, 1) * temp1(i, 1);
}

double a = num_a / den;
double b = num_b / den;

double theta = atan(b / a);
double scale = sqrt(pow(a, 2) + pow(b, 2));
double cos_theta = cos(theta);
double sin_theta = sin(theta);
rotation(0,0) = cos_theta;
rotation(0,1) = -sin_theta;
rotation(1,0) = sin_theta;
rotation(1,1) = cos_theta;

}

There's an error due to redefinition of scale, so remove the double before scale near the end.