#include "MRegressionLinear.h"
//-------------------------------------------------------------------------------
// コンストラクタ RGB同時計算向けに係数次元を3倍する
CMRegressionLinear::CMRegressionLinear(void) : CMRegression(LINEARIZE_DIM * 3)
{
}
//-------------------------------------------------------------------------------
// デストラクタ
CMRegressionLinear::~CMRegressionLinear(void)
{
}
//-------------------------------------------------------------------------------
// 推定行列の算出に使う値を返す
double CMRegressionLinear::GetX(const CvMat *mat, const int sample, const int index)
{
CvScalar v = cvGet2D(mat, sample, index / LINEARIZE_DIM);
return pow(v.val[0], (double)(index % LINEARIZE_DIM));
}
//-------------------------------------------------------------------------------
// 係数の重回帰推定
bool CMRegressionLinear::CalcCoef(const CvMat *macbethX)
{
// 無彩色パッチを抜き出す(19〜24番)
CvMat rgbX = cvMat(NUM_PATCH_LINEARIZE, macbethX->cols, CV_64FC1, NULL);
cvGetRows(macbethX, &rgbX, 18, 24);
double reflectance[] = REFLECTANCE_LIST;
CvMat y = cvMat(NUM_PATCH_LINEARIZE, 1, CV_64FC1, reflectance);
CvMat x = cvMat(NUM_PATCH_LINEARIZE, 1, CV_64FC1, NULL);
CvMat *coef = cvCreateMat(m_Dim, rgbX.cols, CV_64FC1);
cvSetZero(coef);
// 色別に処理
m_Dim = LINEARIZE_DIM; // 一時的に係数次元を1色分に落とす
for (int col = 0; col < rgbX.cols; col ++)
{
// 1色取り出す
cvGetCol(&rgbX, &x, col);
// 色別に係数の算出
CALL(CMRegression::CalcCoef(&x, &y));
// 算出した係数,誤差をコピーする
for(int i = 0; i < m_Coef->rows; i ++)
cvmSet(coef, i + col * LINEARIZE_DIM, col, GcvmGet(m_Coef, i, 0));
cvReleaseData(&x);
}
// RGB同時計算向けに係数次元を3倍に戻す
m_Dim = LINEARIZE_DIM * 3;
// 係数行列をメンバー変数に保存する
SAFE_RELEASEMAT(m_Coef);
m_Coef = (CvMat*)cvClone(coef);
#ifdef SHOW_REGRESSION_COEF
GShowMat(m_Coef, "CoefLinearize", "%9.6f");
// 誤差の計算
double reflectance3[] = REFLECTANCE_LIST3;
CvMat y3 = cvMat(NUM_PATCH_LINEARIZE, 3, CV_64FC1, reflectance3);
CALL(CMRegression::CalcError(&rgbX, &y3));
GShowMat(m_Error, "Estimation error", "%9.6f");
#endif // SHOW_REGRESSION_COEF
// 行列の解放
SAFE_RELEASEMAT(coef);
cvReleaseData(&rgbX);
return true;
}
//-------------------------------------------------------------------------------
// フィッティングカーブの算出
bool CMRegressionLinear::CalcCurve()
{
// 入力値行列作成
const int Steps = 256;
CvMat *fitData = cvCreateMat(Steps, m_Dim, CV_64FC1);
for (int sample = 0; sample < Steps; sample ++)
{
for (int i = 0; i < m_Dim; i++)
{
cvmSet(fitData, sample, i,
pow((double)sample, (double)(i % LINEARIZE_DIM)));
}
}
// フィッティングカーブの算出
CvMat *fitCurve = cvCreateMat(Steps, m_Coef->cols, CV_64FC1);
cvMatMul(fitData, m_Coef, fitCurve);
GShowMat(fitCurve, "Fitting Curve", "%7.4f");
// 行列の解放
SAFE_RELEASEMAT(fitData);
SAFE_RELEASEMAT(fitCurve);
return true;
}
//-------------------------------------------------------------------------------
// 変換した行列データを生成する
CvMat *CMRegressionLinear::GenConvert(const CvMat *data)
{
// GetXを使わないで計算する
return GenConvertNoGetX(data);
// 従来の処理へ
// return CMRegression::GenConvert(data);
// RGBチャネル毎に計算する(遅い)
// return GenConvertEachCh(data);
}
//-------------------------------------------------------------------------------
// 変換した行列データを生成する(RGB別に処理するバージョン:遅かった)
CvMat *CMRegressionLinear::GenConvertEachCh(const CvMat *data)
{
// m_Dim を一時的に変更
m_Dim = LINEARIZE_DIM;
// 行列の確保
CvMat *convert = cvCreateMat(data->rows, data->cols, CV_64FC1);
CvMat *sCoef = cvCreateMat(LINEARIZE_DIM, 1, CV_64F);
CvMat *sConvert = cvCreateMat(data->rows, 1, CV_64F);
// 各色の処理
for (int col = 0; col < COLOR; col ++)
{
// 係数抜き出し
for (int i = 0; i < LINEARIZE_DIM; i ++)
cvmSet(sCoef, i, 0, cvmGet(m_Coef, col * LINEARIZE_DIM + i, col));
// データ抜き出し
CvMat sData = cvMat(data->rows, 1, data->type);
cvGetCol(data, &sData, col);
// データ行列作成
CvMat *matData = GenDataMat(&sData);
// 推定値の算出
cvMatMul(matData, sCoef, sConvert);
// 推定値を出力行列に書き込む
for (int i = 0; i < data->rows; i ++)
cvmSet(convert, i, col, cvmGet(sConvert, i, 0));
SAFE_RELEASEMAT(matData);
}
// m_Dim を戻す
m_Dim = LINEARIZE_DIM * 3;
// 計算に使用した行列の解放
SAFE_RELEASEMAT(sCoef);
SAFE_RELEASEMAT(sConvert);
return convert;
}
//-------------------------------------------------------------------------------
// 変換した行列データを生成する(GetXを使わないバージョン)
CvMat *CMRegressionLinear::GenConvertNoGetX(const CvMat *data)
{
assert(LINEARIZE_DIM == 4);
// 行列の確保
CvMat *convert = cvCreateMat(data->rows, data->cols, CV_64FC1);
// 係数の取得
double b0[COLOR], b1[COLOR], b2[COLOR], b3[COLOR];
for (int col = 0; col < data->cols; col ++)
{
b0[col] = cvmGet(m_Coef, col * LINEARIZE_DIM , col);
b1[col] = cvmGet(m_Coef, col * LINEARIZE_DIM + 1, col);
b2[col] = cvmGet(m_Coef, col * LINEARIZE_DIM + 2, col);
b3[col] = cvmGet(m_Coef, col * LINEARIZE_DIM + 3, col);
}
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int sample = 0; sample < data->rows; sample ++)
{
for (int col = 0; col < data->cols; col ++)
{
CvScalar v = cvGet2D(data, sample, col);
// double x = cvmGet(data, sample, col);
double y = b0[col] + b1[col] * v.val[0]
+ b2[col] * v.val[0] * v.val[0]
+ b3[col] * v.val[0] * v.val[0] * v.val[0];
cvmSet(convert, sample, col, y);
}
}
return convert;
}
//-------------------------------------------------------------------------------
// 画像を変換しデータを生成する(係数行列が計算済みであることが前提)
IplImage *CMRegressionLinear::GenConvert(const IplImage *dataImg)
{
return CMRegression::GenConvert(dataImg);
}