アフィニティ変換OpenCVによる最小二乗最適化


アフィニティ変換OpenCVによる最小二乗最適化
本文は@lonelyライヴから出品します。転載は出所を明記してください。記事のリンク:http://blog.csdn.net/lonelyrains/article/details/49865683
// opencv            :
cv::Mat cv::getAffineTransform( const Point2f src[], const Point2f dst[] )
{
    Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.ptr());
    double a[6*6], b[6];
    Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b);

    for( int i = 0; i < 3; i++ )
    {
        int j = i*12;
        int k = i*12+6;
        a[j] = a[k+3] = src[i].x;
        a[j+1] = a[k+4] = src[i].y;
        a[j+2] = a[k+5] = 1;
        a[j+3] = a[j+4] = a[j+5] = 0;
        a[k] = a[k+1] = a[k+2] = 0;
        b[i*2] = dst[i].x;
        b[i*2+1] = dst[i].y;
    }

    solve( A, B, X );
    return M;
}
この関数は3つの点のアフィニティ変換だけを受けています。サンプルポイントが3つ以上の点を処理することはできません。最小二乗で最も近いアフィニティ変換を探したいです。ですから、本関数の実現を修正しました。次のように定義しました。
//       ,    ,             
cv::Mat myGetAffineTransform(const cv::Point2f src[], const cv::Point2f dst[], int m)
{
    cv::Mat_<float> X = cv::Mat(m, 3, CV_32FC1, cv::Scalar(0));
    cv::Mat_<float> Y = cv::Mat(m, 2, CV_32FC1, cv::Scalar(0));

    for (int i = 0; i < m; i++)
    {
        float x0 = src[i].x, x1 = src[i].y;
        float y0 = dst[i].x, y1 = dst[i].y;

        X(i, 0) = x0;
        X(i, 1) = x1;
        X(i, 2) = 1;

        Y(i, 0) = y0;
        Y(i, 1) = y1;
    }

    cv::Mat_<float> F = (X.t()*X).inv()*(X.t()*Y);

    // cout << F << endl;

    return F.t();
}
本実施は最小二乗の正規行列法に基づいて解いた。ちょうど前の機械学習の文章と呼応します。参考できる:マシン学習(四)正規方程式は、線形回帰問題、正規方法と勾配法の優劣を解く。