#include "Analysis.h"
//-------------------------------------------------------------------------------
// コンストラクタ
CAnalysis::CAnalysis(void)
{
m_RefProc = new CReferenceProc;
m_Casmatch = new CDetectCasmatch;
m_Tracker = new CTracking;
m_NumProcFrames = 0;
}
//-------------------------------------------------------------------------------
// デストラクタ
CAnalysis::~CAnalysis(void)
{
SAFE_DELETE(m_RefProc);
SAFE_DELETE(m_Casmatch);
SAFE_DELETE(m_Tracker);
destroyAllWindows();
}
//-------------------------------------------------------------------------------
// 全般的な初期化
bool CAnalysis::GlobalInit()
{
#ifndef DEBUG_TRACK_ONLY
CALL(m_RefProc->Init());
CALL(m_Casmatch->Init());
#endif
return true;
}
//-------------------------------------------------------------------------------
// 全体処理
bool CAnalysis::GlobalProc()
{
printf("Toungue Analysis ver.%s\n\n", VERSION);
CALL(this->GlobalInit());
CProcessList pl;
CALL(pl.Init());
FILE *fp;
char filename[PATH_LEN];
sprintf_s(filename, PATH_LEN, "%s\\%s", GOUT_DIR, ANALYSIS_FILE);
fopen_s(&fp, filename, "w");
if (!fp) ERROR_RET("Can't open Global log file.");
fprintf(fp, "日付, 時間-被験者, 解析ファイル, "
//"エラー, 処理枚数, 動き, "
//"L1(t0), a1(t0), b1(t0), L1(t10), a1(t10), b1(t10), "
//"L1(t20), a1(t20), b1(t20), L1(t30), a1(t30), b1(t30), "
//"L2(t0), a2(t0), b2(t0), L2(t10), a2(t10), b2(t10), "
//"L2(t20), a2(t20), b2(t20), L2(t30), a2(t30), b2(t30), "
//"L3(t0), a3(t0), b3(t0), L3(t10), a3(t10), b3(t10), "
//"L3(t20), a3(t20), b3(t20), L3(t30), a3(t30), b3(t30), "
//"L4(t0), a4(t0), b4(t0), L4(t10), a4(t10), b4(t10), "
//"L4(t20), a4(t20), b4(t20), L4(t30), a4(t30), b4(t30), "
"L1(t0), a1(t0), b1(t0), "
"L2(t0), a2(t0), b2(t0), "
"L3(t0), a3(t0), b3(t0), "
"L4(t0), a4(t0), b4(t0), "
"\n");
bool noRefInfo = false;
do
{
char workpath[PATH_LEN] = "";
#ifndef DEBUG_TRACK_ONLY
if (pl.IsFirstTOD())
{
printf("校正色票解析\n");
char outputFile[PATH_LEN];
sprintf_s(outputFile, PATH_LEN, "%s\\%s_calib.jpg", GOUT_DIR, pl.CurrentDate());
if (m_RefProc->CalcMatrix(pl.CurrentRefFile(), outputFile)) noRefInfo = false;
else noRefInfo = true;
}
#endif
if (noRefInfo) continue;
if(!pl.GetFrameDir(workpath)) continue;
printf("舌色解析 %s\n", workpath);
int err = this->MeasurementProc(workpath, IMAGE_FILE, pl);
// if (err == -1) continue;
// ログに出力
char buffer[256];
pl.MakeParamStr(buffer, sizeof(buffer));
fprintf(fp, "%s, ", buffer);
sprintf_s(buffer, 256, IMAGE_FILE, pl.GetSelectFrame());
fprintf(fp, "%s, ", buffer);
//fprintf(fp, "%d, %d, %f, ",
// err, m_NumProcFrames, m_Tracker->TotalMovement() / m_NumProcFrames);
if (err > 0) {
fprintf(fp, "\n");
continue;
}
// ログに出力(領域1)
for (int i = 0; i < ((m_NumProcFrames - 1) / m_FrameScale) + 1; i++)
{
fprintf(fp, "%.3f, %.3f, %.3f, ",
m_ROILabT1[i].val[0], m_ROILabT1[i].val[1], m_ROILabT1[i].val[2]);
}
//for (int i = ((m_NumProcFrames - 1) / m_FrameScale) + 1; i < 4; i++)
//{
// fprintf(fp, " , , , ");
//}
// ログに出力(領域2)
for (int i = 0; i < ((m_NumProcFrames - 1) / m_FrameScale) + 1; i++)
{
fprintf(fp, "%.3f, %.3f, %.3f, ",
m_ROILabT2[i].val[0], m_ROILabT2[i].val[1], m_ROILabT2[i].val[2]);
}
//for (int i = ((m_NumProcFrames - 1) / m_FrameScale) + 1; i < 4; i++)
//{
// fprintf(fp, " , , , ");
//}
// ログに出力(領域3)
for (int i = 0; i < ((m_NumProcFrames - 1) / m_FrameScale) + 1; i++)
{
fprintf(fp, "%.3f, %.3f, %.3f, ",
m_ROILabT3[i].val[0], m_ROILabT3[i].val[1], m_ROILabT3[i].val[2]);
}
//for (int i = ((m_NumProcFrames - 1) / m_FrameScale) + 1; i < 4; i++)
//{
// fprintf(fp, " , , , ");
//}
// ログに出力(領域4)
for (int i = 0; i < ((m_NumProcFrames - 1) / m_FrameScale) + 1; i++)
{
fprintf(fp, "%.3f, %.3f, %.3f, ",
m_ROILabT4[i].val[0], m_ROILabT4[i].val[1], m_ROILabT4[i].val[2]);
}
//for (int i = ((m_NumProcFrames - 1) / m_FrameScale) + 1; i < 4; i++)
//{
// fprintf(fp, " , , , ");
//}
fprintf(fp, "\n");
} while(pl.MoveNext());
fclose(fp);
printf("\nFinished.\n");
if (GShowImage(NULL, 0) < 1)
{
printf("Press key on terminal.\n");
getchar();
}
else
{
printf("Press key on window.\n");
cvWaitKey(0);
}
return true;
}
//-------------------------------------------------------------------------------
// 撮影処理
// 戻り値 エラー値 int 0=OK 10=画像ファイル無し 11=パラメータファイル読込失敗
// 12=処理画像無し
//
int CAnalysis::MeasurementProc(const char *path, const char *file, CProcessList &pl)
{
// 画像枚数と手動抽出パラメータの取得
int numFrames = GetNumFrames(path, file);
if (numFrames < 1)
{
printf("No measurement file found.\n");
return 10;
}
int frame0 = ReadParam(path);
if (frame0 < 1)
{
printf("Read param failed.\n");
return 11;
}
pl.SetSelectFrame(frame0);
// 処理画像枚数の決定
int procFrames = (numFrames < (PROC_FRAMES_S + PROC_FRAMES_L) / 2 ?
PROC_FRAMES_S : PROC_FRAMES_L);
m_FrameScale = (procFrames == PROC_FRAMES_S ? 10 : 100);
#ifdef DEBUG_NUM_FRAMES
procFrames = DEBUG_NUM_FRAMES;
#endif
// 処理画像を開く
char filename[PATH_LEN], filenam2[PATH_LEN]; // 処理画像ファイル名
sprintf_s(filenam2, PATH_LEN, file, frame0);
sprintf_s(filename, PATH_LEN, "%s\\%s", path, filenam2);
if (!PathFileExists(filename))
{
printf("Selected file does not exist.\n");
return 12;
}
#ifndef DEBUG_TRACK_ONLY
#ifndef NO_CASMATCH
// キャスマッチの検出,パッチ色取得
CALL(m_Casmatch->SetImage(filename));
CALL(m_Casmatch->Detect());
#endif // NO_CASMATCH
#endif // DEBUG_TRACK_ONLY
// トラッキングの初期化
IplImage *img = cvLoadImage(filename);
#ifdef ROTATE_IMAGE
IplImage* imgRot = cvCreateImage(cvSize(img->height, img->width), img->depth, img->nChannels);
cvTranspose(img, imgRot);
cvFlip(imgRot, NULL, 1);
m_Tracker->Init(m_InitTrack, TRACK_POINTS, imgRot);
SAFE_RELEASEIMG(imgRot);
#else
m_Tracker->Init(m_InitTrack, TRACK_POINTS, img);
#endif
// m_Tracker->DrawPoints(img);
// GShowImage(img, 1, "Init Tracker");
SAFE_RELEASEIMG(img);
// 結果出力ディレクトリの作成
sprintf_s(filename, PATH_LEN, LOUT_DIR, path);
if (!GFileExists(filename)) CreateDirectory(filename, NULL);
// ログの準備
FILE *fpLog;
sprintf_s(filename, PATH_LEN, "%s\\%s", path, ANALYSIS_FILE);
fopen_s(&fpLog, filename, "w");
if (!fpLog) ERROR_RET("Can't open local log file.");
fprintf(fpLog, "フレーム, 動き, L*1, a*1, b*1, L*2, a*2, b*2, L*3, a*3, b*3, L*4, a*4, b*4\n");
// 各フレームの処理
int err = 0;
m_NumProcFrames = 0;
for (int frame = frame0; frame < frame0 + procFrames && err == 0; frame ++)
{
printf("\n* Frame %d\n", m_NumProcFrames);
sprintf_s(filenam2, PATH_LEN, file, frame);
sprintf_s(filename, PATH_LEN, "%s\\%s", path, filenam2);
err = this->FrameProc(filename, path, m_NumProcFrames, fpLog, pl);
if (err > -1) m_NumProcFrames ++;
}
#ifdef MANUAL_TRACKING_EVALUATION
// 終了後に手動でトラッキング結果を評価する
if (err == 0)
{
printf("Evaluate result pressing key [F]ailed or key else on the win:\n");
if (cvWaitKey(0) == 'f') err = 3;
}
#endif // MANUAL_TRACKING_EVALUATION
fclose(fpLog);
return err;
}
//-------------------------------------------------------------------------------
// フレーム処理
// 戻り値 エラー値 int 0=OK 1=特徴点位置不正 2=特徴点消失
// -1=致命的なエラー -2=画像なしエラー
//
int CAnalysis::FrameProc(const char *inputfile, const char *path,
const int frame, FILE *fpLog, CProcessList &pl)
{
int trackErr = 0;
CHQTime timer;
// ファイルを開く
IplImage *imgCam = cvLoadImage(inputfile);
if (!imgCam)
{
printf("Error: No camera file.\n");
return -2;
}
#ifdef ROTATE_IMAGE
IplImage* imgRot = cvCreateImage(cvSize(imgCam->height, imgCam->width), imgCam->depth, imgCam->nChannels);
cvTranspose(imgCam, imgRot);
cvFlip(imgRot, NULL, 1);
SAFE_RELEASEIMG(imgCam);
imgCam = (IplImage*)cvClone(imgRot);
#endif
// トラッキング
if (!m_Tracker->Frame(imgCam))
{
printf("Track point missing.\n");
trackErr = 2;
}
fprintf(fpLog, "%d, %f, ", frame, m_Tracker->Movement());
if (!m_Tracker->IsVaildate())
{
printf("Track position invalidate.\n");
trackErr = 1;
}
timer.LapTime("tracking");
#ifndef DEBUG_TRACK_ONLY
#ifndef NO_CASMATCH
// キャスマッチのパッチ色取得
CvMat *crgbFC = NULL;
CALL(m_Casmatch->SetImage(inputfile));
CALL(m_Casmatch->CalcPatchColor9(&crgbFC));
#ifdef SHOW_RGB_VALUES
GShowMat(crgbFC, "crgbFC", "%5.1f");
#endif // SHOW_RGB_VALUES
// 線形化
CvMat *lrgbFC = m_RefProc->GenLinearize(crgbFC);
#ifdef SHOW_RGB_VALUES
GShowMat(lrgbFC, "lrgbFC", "%6.1f");
#endif // SHOW_RGB_VALUES
// フレーム間色補正行列の算出
CMRegressionRGB ccmFR(FRAME_REF_CONVERT_DIM);
#ifdef SHOW_REGRESSION_COEF
printf("ccmFR ");
#endif // SHOW_REGRESSION_COEF
ccmFR.CalcCoef(lrgbFC, m_RefProc->lrgbRC());
#endif // NO_CASMATCH
timer.LapTime("coef calculation");
if (trackErr == 0)
{
// ROIの計算(マスク1)
CvScalar roiCam1 = m_Tracker->ROIColor1(imgCam);
CvScalar roiLin1 = m_RefProc->ScalarLinearize(roiCam1);
#ifndef NO_CASMATCH
CvScalar roiCor1 = ccmFR.ScalarConvert(roiLin1);
printf("roiLin1 = %f, %f, %f\n",
roiLin1.val[0], roiLin1.val[1], roiLin1.val[2]);
printf("roiCor1 = %f, %f, %f\n",
roiCor1.val[0], roiCor1.val[1], roiCor1.val[2]);
CvScalar roiXYZ1 = m_RefProc->ScalarConvertXYZ(roiCor1);
#else
CvScalar roiXYZ1 = m_RefProc->ScalarConvertXYZ(roiLin1);
#endif // NO_CASMATCH
CvScalar roiLab1 = GXYZtoLab(roiXYZ1);
printf("Lab1 = %f, %f, %f\n",
roiLab1.val[0], roiLab1.val[1], roiLab1.val[2]);
fprintf(fpLog, "%f, %f, %f, ",
roiLab1.val[0], roiLab1.val[1], roiLab1.val[2]);
if (frame % m_FrameScale == 0)
m_ROILabT1[frame / m_FrameScale] = roiLab1;
// ROIの計算(マスク2)
CvScalar roiCam2 = m_Tracker->ROIColor2(imgCam);
CvScalar roiLin2 = m_RefProc->ScalarLinearize(roiCam2);
#ifndef NO_CASMATCH
CvScalar roiCor2 = ccmFR.ScalarConvert(roiLin2);
CvScalar roiXYZ2 = m_RefProc->ScalarConvertXYZ(roiCor2);
#else
CvScalar roiXYZ2 = m_RefProc->ScalarConvertXYZ(roiLin2);
#endif // NO_CASMATCH
CvScalar roiLab2 = GXYZtoLab(roiXYZ2);
printf("Lab2 = %f, %f, %f\n",
roiLab2.val[0], roiLab2.val[1], roiLab2.val[2]);
fprintf(fpLog, "%f, %f, %f, ",
roiLab2.val[0], roiLab2.val[1], roiLab2.val[2]);
if (frame % m_FrameScale == 0)
m_ROILabT2[frame / m_FrameScale] = roiLab2;
// ROIの計算(マスク3)
CvScalar roiCam3 = m_Tracker->ROIColor3(imgCam);
CvScalar roiLin3 = m_RefProc->ScalarLinearize(roiCam3);
#ifndef NO_CASMATCH
CvScalar roiCor3 = ccmFR.ScalarConvert(roiLin3);
CvScalar roiXYZ3 = m_RefProc->ScalarConvertXYZ(roiCor3);
#else
CvScalar roiXYZ3 = m_RefProc->ScalarConvertXYZ(roiLin3);
#endif // NO_CASMATCH
CvScalar roiLab3 = GXYZtoLab(roiXYZ3);
printf("Lab3 = %f, %f, %f\n",
roiLab3.val[0], roiLab3.val[1], roiLab3.val[2]);
fprintf(fpLog, "%f, %f, %f, ",
roiLab3.val[0], roiLab3.val[1], roiLab3.val[2]);
if (frame % m_FrameScale == 0)
m_ROILabT3[frame / m_FrameScale] = roiLab3;
// ROIの計算(マスク4)
CvScalar roiCam4 = m_Tracker->ROIColor4(imgCam);
CvScalar roiLin4 = m_RefProc->ScalarLinearize(roiCam4);
#ifndef NO_CASMATCH
CvScalar roiCor4 = ccmFR.ScalarConvert(roiLin4);
CvScalar roiXYZ4 = m_RefProc->ScalarConvertXYZ(roiCor4);
#else
CvScalar roiXYZ4 = m_RefProc->ScalarConvertXYZ(roiLin4);
#endif // NO_CASMATCH
CvScalar roiLab4 = GXYZtoLab(roiXYZ4);
printf("Lab4 = %f, %f, %f\n",
roiLab4.val[0], roiLab4.val[1], roiLab4.val[2]);
fprintf(fpLog, "%f, %f, %f, ",
roiLab4.val[0], roiLab4.val[1], roiLab4.val[2]);
if (frame % m_FrameScale == 0)
m_ROILabT4[frame / m_FrameScale] = roiLab4;
}
#ifdef CONVERT_IMAGE
// 画像の色変換
IplImage *imgLin = m_RefProc->GenLinearize(imgCam);
timer.LapTime("image linearize");
IplImage *imgCor = ccmFR.GenConvert(imgLin);
timer.LapTime("image correction");
// XYZに変換
IplImage *imgXYZ = m_RefProc->GenConvertXYZ(imgCor);
timer.LapTime("image conversion to XYZ");
// モニター用に変換
IplImage *imgDisp = m_RefProc->GenConvertDisp(imgXYZ);
timer.LapTime("image conversion to Monitor RGB");
IplImage *imgGamma = GGenAddGamma(imgDisp);
timer.LapTime("image conversion adding Gamma");
#endif // CONVERT_IMAGE
#endif // DEBUG_TRACK_ONLY
// 解析結果の表示
#ifndef DEBUG_TRACK_ONLY
#ifndef NO_CASMATCH
IplImage *imgCV = m_Casmatch->GenPatchedImage();
#else
// IplImage *imgCV = cvLoadImage(inputfile);
#endif
m_Tracker->DrawPoints(imgCam);
if (trackErr == 0) m_Tracker->DrawROI(imgCam);
#ifdef SHOW_CV_IMAGE
GShowImage(imgCam, 1, "Detection result");
#endif // SHOW_CV_IMAGE
#ifdef CONVERT_IMAGE
GShowImage(imgGamma, 2, "Calibrated");
#endif // CONVERT_IMAGE
#ifdef SHOW_XYZ_IMAGE
//IplImage *imgX = cvCreateImage(cvGetSize(imgXYZ), IPL_DEPTH_64F, 1);
//IplImage *imgY = cvCreateImage(cvGetSize(imgXYZ), IPL_DEPTH_64F, 1);
//IplImage *imgZ = cvCreateImage(cvGetSize(imgXYZ), IPL_DEPTH_64F, 1);
//cvSplit(imgXYZ, imgX, imgY, imgZ, NULL);
//GShowImage(imgX, 3, "X image");
//GShowImage(imgY, 4, "Y image");
//GShowImage(imgZ, 5, "Z image");
#endif // SHOW_XYZ_IMAGE
#else // DEBUG_TRACK_ONLY
m_Tracker->DrawPoints(imgCam);
if (trackErr < 1) GShowImage(imgCam, 1, "Detection result", 1);
else GShowImage(imgCam, 1, "Tracking failed", 1);
#endif // DEBUG_TRACK_ONLY
timer.LapTime("display");
// 解析結果の保存
char filename[PATH_LEN];
sprintf_s(filename, PATH_LEN, LOUT_CVFILE, path, frame);
cvSaveImage(filename, imgCam);
// 最初の一枚を全体結果フォルダに保存
if (frame < 1) {
char buffer[PATH_LEN];
pl.MakeFileStr(buffer, PATH_LEN);
sprintf_s(filename, PATH_LEN, "%s\\%s.jpg", GOUT_DIR, buffer);
cvSaveImage(filename, imgCam);
}
timer.LapTime("save image");
// 計算に使用した行列の解放
SAFE_RELEASEIMG(imgCam);
#ifndef DEBUG_TRACK_ONLY
#ifndef NO_CASMATCH
SAFE_RELEASEMAT(crgbFC);
SAFE_RELEASEMAT(lrgbFC);
#endif // NO_CASMATCH
#ifdef CONVERT_IMAGE
SAFE_RELEASEIMG(imgLin);
SAFE_RELEASEIMG(imgCor);
SAFE_RELEASEIMG(imgXYZ);
SAFE_RELEASEIMG(imgDisp);
SAFE_RELEASEIMG(imgGamma);
#endif // CONVERT_IMAGE
#ifdef SHOW_XYZ_IMAGE
SAFE_RELEASEIMG(imgX);
SAFE_RELEASEIMG(imgY);
SAFE_RELEASEIMG(imgZ);
#endif // SHOW_XYZ_IMAGE
#endif // DEBUG_TRACK_ONLY
fprintf(fpLog, "\n");
timer.CheckTime("FrameProc");
return trackErr;
}
//-------------------------------------------------------------------------------
// フレーム数の取得
int CAnalysis::GetNumFrames(const char *path, const char *file)
{
char filename[PATH_LEN], filenam2[PATH_LEN];
sprintf_s(filenam2, PATH_LEN, file, 0);
sprintf_s(filename, PATH_LEN, "%s\\%s", path, filenam2);
int frame = GFileExists(filename) ? -1 : 0;
do
{
sprintf_s(filenam2, PATH_LEN, file, ++ frame);
sprintf_s(filename, PATH_LEN, "%s\\%s", path, filenam2);
} while (GFileExists(filename));
frame--;
printf("Found %d frames\n", frame);
return frame;
}
//-------------------------------------------------------------------------------
// パラメータを読み込む
int CAnalysis::ReadParam(const char *path)
{
// パラメータファイルを開く
char filename[PATH_LEN];
sprintf_s(filename, PATH_LEN, "%s\\" PARAM_FILE, path);
// パラメータを読み込む
FILE *fp = NULL;
fopen_s(&fp, filename, "r");
if (fp == NULL) ERROR_RET("Can't open parameter file.");
const int BUFFER_LEN = 1024;
char buffer[BUFFER_LEN] = {0};
// 開始フレーム取得
fgets(buffer, BUFFER_LEN, fp);
int firstFrame = 0;
sscanf_s(buffer, IMAGE_FILE, &firstFrame);
#ifdef SHOW_FILELOAD
printf("First frame %d\n", firstFrame);
#endif // SHOW_FILELOAD
// 舌形状ポイントの取得
Point p[TRACK_POINTS];
for (int i = 0; i < TRACK_POINTS; i++)
{
fgets(buffer, BUFFER_LEN, fp);
char *pt = buffer;
for (; *pt != '\0' && *pt != ','; pt ++);
if (*pt != ',') ERROR_RET("Parameter file error.");
*pt = '\0';
p[i].x = atoi(buffer) * 1;
p[i].y = atoi(pt + 1) * 1;
#ifdef SHOW_FILELOAD
printf("Reading track point (%d, %d)\n", p[i].x, p[i].y);
#endif // SHOW_FILELOAD
}
// 並び替える
// 最下点の探索
int by = p[0].y;
for (int i = 1; i < TRACK_POINTS; i++) {
if (p[i].y > by) by = p[i].y;
}
// X方向に並び替え
Point tmp;
for (int i = 0; i < TRACK_POINTS - 1; i++) {
for (int j = i + 1; j < TRACK_POINTS; j++) {
if (p[i].x > p[j].x || p[i].y == -by) {
tmp = p[j];
p[j] = p[i];
p[i] = tmp;
}
}
}
// 最下点を最後に移動
tmp.x = -1;
for (int i = 1; i < TRACK_POINTS-1; i++) {
if (p[i].y == by) tmp = p[i];
if (tmp.x >= 0) p[i] = p[i + 1];
}
p[TRACK_POINTS - 1] = tmp;
// 並び替え結果代入
m_InitTrack[0] = p[0].y < p[1].y ? p[0] : p[1];
m_InitTrack[1] = p[0].y > p[1].y ? p[0] : p[1];
m_InitTrack[2] = p[4];
m_InitTrack[3] = p[2].y > p[3].y ? p[2] : p[3];
m_InitTrack[4] = p[2].y < p[3].y ? p[2] : p[3];
#ifdef SHOW_FILELOAD
// 表示
for (int i = 0; i < TRACK_POINTS; i++) {
printf("Ordered track point (%d, %d)\n", m_InitTrack[i].x, m_InitTrack[i].y);
}
#endif // SHOW_FILELOAD
return firstFrame;
}