最近研究で最小二乗法を用いる機会がありました.今回はその際に用いたopenCVのcvSolveの使い方を説明したいと思います.
解きたい問題
よくある最小二乗法で解きたい問題は以下のような線形方程式になります.
$Y=AX$
ここではYとAが固定されており,この条件下でのXが必要になってきます.私の場合は以下のような問題でした.
$
\begin{equation}
\begin{pmatrix}
x_{1}' &\ldots & \ldots &x_{n}' \\
y_{1}' &\ldots & \ldots &y_{n}' \\
z_{1}' &\ldots & \ldots &z_{n}' \\
1 &1 &1 &1
\end{pmatrix}
= \begin{pmatrix}
a &b &c &tx \\
d &e &f &ty \\
g &h &i &tz \\
0 &0 &0 &1
\end{pmatrix}
\begin{pmatrix}
x_{1} &\ldots & \ldots &x_{n} \\
y_{1} &\ldots & \ldots &y_{n} \\
z_{1} &\ldots & \ldots &z_{n} \\
1 &1 &1 &1
\end{pmatrix}
\end{equation}
$
みたらわかる人も行くかもしれませんがアフィン変換ですね.ある座標からある座標への変換行列の演算を行いました.では,実際のソースコードを以下に示します.
# define _CRT_SECURE_NO_WARNINGS
# include <stdio.h>
# include <opencv\cv.h>
# define SIZE 4
# define COUNT 6
int main(void)
{
CvMat *mA,*mX,*mY;
mA = cvCreateMat(SIZE, SIZE, CV_32F);
mX = cvCreateMat(SIZE, COUNT, CV_32F);
mY = cvCreateMat(SIZE, COUNT, CV_32F);
cvSet(mA, cvScalar(1.0f));
cvSet(mY, cvScalar(2.0f));
// SVDを用いた最小二乗解
cvSolve(mA, mY, mX, CV_SVD);
// 出力
for (int i = 0; i < SIZE; i++)
{
printf("(");
for (int j = 0; j < COUNT; j++)
{
printf("%f ", cvmGet(mY, i, j));
}
printf(") = (");
for (int j = 0; j < SIZE; j++)
{
printf("%f ", cvmGet(mA, i, j));
}
printf(") (");
for (int j = 0; j < COUNT; j++)
{
printf("%f ", cvmGet(mX, i, j));
}
printf(")\n");
}
cvReleaseMat(&mA);
cvReleaseMat(&mX);
cvReleaseMat(&mY);
return 0;
}
見て分かると思いますが A = mA , X = mX , Y=mY となっており,AとYを指定しcvSolve
の引数に入れてあげることでXに結果が代入されるという仕組みになっています.以上です.
参考サイト