ORB_SLAM2 计算 F21 的代码是这样的。
cv::Mat Initializer::ComputeF21(const vector<cv::Point2f> &vP1,const vector<cv::Point2f> &vP2)
{
const int N = vP1.size();
cv::Mat A(N,9,CV_32F);
for(int i=0; i<N; i++)
{
const float u1 = vP1[i].x;
const float v1 = vP1[i].y;
const float u2 = vP2[i].x;
const float v2 = vP2[i].y;
A.at<float>(i,0) = u2*u1;
A.at<float>(i,1) = u2*v1;
A.at<float>(i,2) = u2;
A.at<float>(i,3) = v2*u1;
A.at<float>(i,4) = v2*v1;
A.at<float>(i,5) = v2;
A.at<float>(i,6) = u1;
A.at<float>(i,7) = v1;
A.at<float>(i,8) = 1;
}
cv::Mat u,w,vt;
cv::SVDecomp(A,w,u,vt,cv::SVD::MODIFY_A | cv::SVD::FULL_UV);
cv::Mat Fpre = vt.row(8).reshape(0, 3);
cv::SVDecomp(Fpre,w,u,vt,cv::SVD::MODIFY_A | cv::SVD::FULL_UV);
w.at<float>(2)=0;
return u*cv::Mat::diag(w)*vt;
}
F21 的真正意思是:
\[ x_2^TF_{21}x_1^T=0 \]
而写成克罗内克积的形式应该是这样的:
\[ (x_1 \otimes x_2)^TF_{21}^s = 0 \]
而
\[ (x_1 \otimes x_2)^T = [ u_1 u_2, u_1 v_2, u_1, v_1 u_2, v_1 v_2, v_1, u_2, v_2, 1 ]^T \]
这样上面的代码不是写错了吗?
不,OpenCV 是“ROW stack”,而数学公式里面写的是“COL stack”。
OpenCV:
\[F_{21}^s = [f_{11}, f_{12}, f_{13}, …, f_{31}, f_{32}, f_{33}]^T\]
数学公式:
\[F_{21}^s = [f_{11}, f_{21}, f_{31}, …, f_{13}, f_{23}, f_{33}]^T\]
总结
“ROW stack”用$ (x_2 \otimes x_1)^T $ 计算 \(F_{21}\)。“COL stack”用$ (x_1 \otimes x_2)^T $,计算 \(F_{21}\)。