#include "MRegression.h"
//-------------------------------------------------------------------------------
// コンストラクタ
CMRegression::CMRegression(const int dim)
{
m_Coef = NULL;
m_Error = NULL;
m_Dim = dim;
}
//-------------------------------------------------------------------------------
// デストラクタ
CMRegression::~CMRegression(void)
{
SAFE_RELEASEMAT(m_Coef);
SAFE_RELEASEMAT(m_Error);
}
//-------------------------------------------------------------------------------
// 係数の重回帰推定
bool CMRegression::CalcCoef(const CvMat *data, const CvMat *observ)
{
int numSample = data->rows; // サンプル数
int numCh = observ->cols; // 観測値チャネル数
// 行列の確保
CvMat *matData = cvCreateMat(m_Dim, m_Dim, CV_64FC1);
CvMat *matDataInv = cvCreateMat(m_Dim, m_Dim, CV_64FC1);
CvMat *matObsv = cvCreateMat(m_Dim, numCh, CV_64FC1);
// データ行列を求める
for (int row = 0; row < m_Dim; row ++)
{
for (int col = 0; col < m_Dim; col ++)
{
double val = 0;
for (int sample = 0; sample < numSample; sample ++)
val += (GetX(data, sample, row) * GetX(data, sample, col));
cvmSet(matData, row, col, val);
}
}
// データ行列の逆行列を求める
cvInvert(matData, matDataInv, CV_LU);
// 右辺行列を求める
for (int row = 0; row < m_Dim; row ++)
{
for (int col = 0; col < numCh; col ++)
{
double val = 0;
for (int sample = 0; sample < numSample; sample ++)
val += (GetX(data, sample, row) * GcvmGet(observ, sample, col));
cvmSet(matObsv, row, col, val);
}
}
// 係数行列を求める
SAFE_RELEASEMAT(m_Coef);
m_Coef = cvCreateMat(m_Dim, numCh, CV_64FC1);
cvMatMul(matDataInv, matObsv, m_Coef);
// 計算に使用した行列の解放
SAFE_RELEASEMAT(matData);
SAFE_RELEASEMAT(matDataInv);
SAFE_RELEASEMAT(matObsv);
return true;
}
//-------------------------------------------------------------------------------
// データ行列を生成する
CvMat * CMRegression::GenDataMat(const CvMat *data)
{
// データ行列作成
CvMat *matData = cvCreateMat(data->rows, m_Dim, CV_64FC1);
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int sample = 0; sample < data->rows; sample ++)
{
for (int i = 0; i < m_Dim; i++)
{
cvmSet(matData, sample, i, GetX(data, sample, i));
}
}
return matData;
}
//-------------------------------------------------------------------------------
// 推定誤差を計算する
bool CMRegression::CalcError(const CvMat *data, const CvMat *observ)
{
int numSample = data->rows; // サンプル数
int numCh = observ->cols; // 観測値チャネル数
// 推定値の算出
CvMat *estim = GenConvert(data);
// RMSEの算出
SAFE_RELEASEMAT(m_Error);
m_Error = cvCreateMat(1, numCh, CV_64FC1);
for (int col = 0; col < numCh; col ++)
{
double err = 0;
for (int sample = 0; sample < numSample; sample ++)
{
err += pow(GcvmGet(observ, sample, col) - GcvmGet(estim, sample, col),
2.0);
}
cvmSet(m_Error, 0, col, sqrt(err / (double)numSample));
}
// 計算に使用した行列の解放
SAFE_RELEASEMAT(estim);
return true;
}
//-------------------------------------------------------------------------------
// 変換した行列データを生成する(係数行列が計算済みであることが前提)
CvMat *CMRegression::GenConvert(const CvMat *data)
{
// CHQTime timer;
// データ行列作成
CvMat *matData = GenDataMat(data);
// timer.LapTime("GenDataMat");
// 推定値の算出
CvMat *convert = cvCreateMat(data->rows, data->cols, CV_64FC1);
cvMatMul(matData, m_Coef, convert);
// timer.LapTime("cvMatMul ");
// 計算に使用した行列の解放
SAFE_RELEASEMAT(matData);
// timer.LapTime("RELEASEMAT");
return convert;
}
//-------------------------------------------------------------------------------
// 画像を変換しデータを生成する(係数行列が計算済みであることが前提)
IplImage *CMRegression::GenConvert(const IplImage *dataImg)
{
// 画像を行列に変換
CvMat dataMat = cvMat(dataImg->width * dataImg->height, COLOR,
(dataImg->depth == IPL_DEPTH_8U ? CV_8UC1 : CV_64F),
dataImg->imageData);
// 重回帰変換
CvMat *convMat = this->GenConvert(&dataMat);
// 算出された行列を画像に戻す
IplImage *convImg =
cvCreateImage(cvGetSize(dataImg), IPL_DEPTH_64F, COLOR);
memcpy(convImg->imageData, convMat->data.ptr, convImg->imageSize);
// 行列を解放
cvReleaseMat(&convMat);
return convImg;
}
bool CMRegression::DrawGraph4913(CvMat *rgb, CvMat *xyz)
{
IplImage *graph = cvCreateImage(cvSize(DISP_W, DISP_H), IPL_DEPTH_8U, COLOR);
cvSet(graph, cvScalarAll(255.0));
CvMat *data = cvCreateMat(256, COLOR, CV_64F);
for (int b = 0; b < 256; b ++) cvmSet(data, b, 0, pow((double)b, 2.2) / 1000.0);
cvCreateMat(256, COLOR, CV_64F);
double yScale = 10.0;
double xScale = 2.0;
double xMin, xMax;
for (int z = 0; z < 1; z ++)
{
// double zv = (z > 15 ? 255.0 : z * 16.0);
int iRGB = 0;
for (int y = 0; y < 17; y ++)
{
// double yv = (y > 15 ? 255.0 : y * 16.0);
for (int x = 0; x < 17; x ++)
{
double x1 = cvmGet(xyz, x + y * 17 + z * (17 * 17), 0);
double y1 = cvmGet(rgb, x + y * 17 + z * (17 * 17), iRGB);
if (x == 0) xMin = x1;
if (x == 16) xMax = x1;
int dx1 = 100 + (int)(x1 * xScale);
int dy1 = 412 - (int)(y1 * yScale);
cvDrawCircle(graph, cvPoint(dx1, dy1), 3,
CV_RGB(0, (x > 15 ? 255.0 : x * 16.0), 0), CV_FILLED);
}
//for (int b = 0; b < 256; b ++)
//{
// cvmSet(data, b, 1, pow((double)gv, 2.2) / 1000.0);
// cvmSet(data, b, 2, pow((double)rv, 2.2) / 1000.0);
//}
//GShowMat(data, "data for graph");
//CvMat *est = this->GenConvert(data);
//for (int b = 0; b < 255; b ++)
//{
// double y1 = cvmGet(est, b, iXYZ);
// int dx1 = 100 + b * 2;
// int dy1 = 412 - (int)(y1 * yScale);
// double y2 = cvmGet(est, b + 1, iXYZ);
// int dx2 = 100 + (b + 1) * 2;
// int dy2 = 412 - (int)(y2 * yScale);
// cvDrawLine(graph, cvPoint(dx1, dy1), cvPoint(dx2, dy2), CV_RGB(0, (g>15 ? 255 : g*16), 0));
//}
//SAFE_RELEASEMAT(est);
}
GShowImage(graph, 1, "X : r = 0", 0);
}
SAFE_RELEASEIMG(graph);
SAFE_RELEASEMAT(data);
return true;
}
//-------------------------------------------------------------------------------
// Scalar値を変換する(係数行列が計算済みであることが前提)
CvScalar CMRegression::ScalarConvert(const CvScalar data)
{
double dataA[3];
dataA[0] = data.val[0];
dataA[1] = data.val[1];
dataA[2] = data.val[2];
CvMat dataMat = cvMat(1, COLOR, CV_64F, dataA);
CvMat *convMat = this->GenConvert(&dataMat);
return cvScalar(cvmGet(convMat, 0, 0), cvmGet(convMat, 0, 1), cvmGet(convMat, 0, 2));
}