diff --git a/ECTrainer2/ECTrainer2.vcxproj b/ECTrainer2/ECTrainer2.vcxproj
index fe83797..f1b0c0f 100644
--- a/ECTrainer2/ECTrainer2.vcxproj
+++ b/ECTrainer2/ECTrainer2.vcxproj
@@ -153,6 +153,7 @@
+
@@ -176,6 +177,7 @@
+
diff --git a/ECTrainer2/ECTrainer2.vcxproj.filters b/ECTrainer2/ECTrainer2.vcxproj.filters
index f78d800..42a1250 100644
--- a/ECTrainer2/ECTrainer2.vcxproj.filters
+++ b/ECTrainer2/ECTrainer2.vcxproj.filters
@@ -75,6 +75,9 @@
ソース ファイル
+
+ ソース ファイル
+
@@ -143,6 +146,9 @@
ヘッダー ファイル
+
+ ヘッダー ファイル
+
diff --git a/ECTrainer2/ECTrainerGUI.cpp b/ECTrainer2/ECTrainerGUI.cpp
index eec6f1c..444356d 100644
--- a/ECTrainer2/ECTrainerGUI.cpp
+++ b/ECTrainer2/ECTrainerGUI.cpp
@@ -184,7 +184,8 @@
cv::imshow(WIN_MAIN, _MainFrame);
// 全画面表示
- if (Ect()->PWorker()->IsNewFullScreenImg() && !Ect()->PDSMovie()->IsPlaying()) {
+ //if (Ect()->PWorker()->IsNewFullScreenImg() && !Ect()->PDSMovie()->IsPlaying()) {
+ if (Ect()->PWorker()->IsNewFullScreenImg()) {
this->MakeFullDispBuffer(Ect()->PWorker()->GetFullScreenImg());
cv::imshow(WIN_DISP, _FullDispBuf);
}
diff --git a/ECTrainer2/Logger.cpp b/ECTrainer2/Logger.cpp
new file mode 100644
index 0000000..3bc47c9
--- /dev/null
+++ b/ECTrainer2/Logger.cpp
@@ -0,0 +1,83 @@
+#include "Logger.h"
+#include "nkcWinUtils.h"
+
+// コンストラクタ
+Logger::Logger()
+ : _logFileName(_T(""))
+{
+
+}
+
+// ファイル出力(static)
+bool Logger::Write(TCHAR* filename, TCHAR* msg) {
+ if (_tcslen(filename) < 1) return false;
+ FILE* fp = NULL;
+ if (_tfopen_s(&fp, filename, _T("a")) != 0) {
+ nkc::wut::DebugPrintf(_T("Can't open data log file.\n"));
+ return false;
+ }
+
+}
+
+// ログ開始
+void Logger::Start(std::string subject, int visit) {
+
+ _logFileName = nkc::wut::Multi2Wide(
+ cv::format(DATA_LOG_FILE, nkc::wut::DateTimeStr().c_str(), subject, visit));
+ nkc::wut::DebugPrintf(_T("Log file : %s\n"), _logFileName.c_str());
+
+ FILE* fp;
+ if (_tfopen_s(&fp, _logFileName.c_str(), _T("w")) != 0) {
+ nkc::wut::DebugPrintf(_T("Can't open data log file.\n"));
+ return;
+ }
+
+ // ヘッダ行
+ _ftprintf(fp, _T("time,stimNo,stimTime,gazeVx,gazeVy,shiftX,shiftY,"
+ "gazeIx,gazeIy,target,contact time,Feedback,TrainLevel,RR,pupilR,pupilL,"
+ "H11,H12,H13,H21,H22,H23,H31,H32,H33\n"));
+
+ fclose(fp);
+}
+
+// ログ出力
+void Logger::Write(Record& r) {
+
+ if (_logFileName.length() < 1) {
+ nkc::wut::DebugPrintf(_T("Log file is not set.\n"));
+ return;
+ }
+
+ FILE* fp = NULL;
+ if (_tfopen_s(&fp, _logFileName.c_str(), _T("a")) != 0) {
+ nkc::wut::DebugPrintf(_T("Can't open data log file.\n"));
+ return;
+ }
+
+ _ftprintf(fp, _T("%.3f"), r.ElapTime); // 経過時間
+ _ftprintf(fp, _T(",%d"), r.StimNo); // 刺激データ番号
+ _ftprintf(fp, _T(",%.3f"), r.SceneTime); // 刺激提示の経過時間
+ _ftprintf(fp, _T(",%.1f,%.1f"), r.GazeV.x, r.GazeV.y); // 注視点(視野カメラ座標)
+ _ftprintf(fp, _T(",%.1f,%.1f"), r.Shift.x, r.Shift.y); // ずれ
+ _ftprintf(fp, _T(",%.1f,%.1f"), r.GazeI.x, r.GazeI.y); // 注視点(画像座標)
+ _ftprintf(fp, _T(",%d"), r.Target); // ターゲット判定
+ _ftprintf(fp, _T(",%.2f"), r.ContactTime); // 目標コンタクト時間
+ _ftprintf(fp, _T(",%d"), r.Feedback); // フィードバック
+ _ftprintf(fp, _T(",%d"), r.TrainingLevel); // トレーニングレベル
+ _ftprintf(fp, _T(",%d"), r.RR); // バイタル出力(RR間隔)
+ _ftprintf(fp, _T(",%.1f,%.1f"), r.PupilR, r.PupilL); // 瞳孔径
+ if (!r.H.empty() && r.H.rows == 3 && r.H.cols == 3) { // ホモグラフィ行列出力
+ double* ptr = r.H.ptr(0);
+ for (int i = 0; i < 9; i++) {
+ _ftprintf(fp, _T(",%lf"), *(ptr + i));
+ }
+ }
+ _ftprintf(fp, _T("\n"));
+
+ fclose(fp);
+}
+
+// ログ停止
+void Logger::Stop() {
+ _logFileName = _T("");
+}
diff --git a/ECTrainer2/Logger.h b/ECTrainer2/Logger.h
new file mode 100644
index 0000000..065c355
--- /dev/null
+++ b/ECTrainer2/Logger.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include "nkcOpenCV.h"
+
+#define LOG_DIR "../log/"
+
+struct Record {
+ double ElapTime; // 経過時間
+ int StimNo; // 刺激データ番号
+ double SceneTime; // 刺激提示の経過時間
+ cv::Point2f GazeV; // 注視点(視野カメラ座標)
+ cv::Point2f Shift; // ずれ
+ cv::Point2f GazeI; // 注視点(画像座標)
+ int Target; // ターゲット判定
+ double ContactTime; // 目標コンタクト時間
+ int Feedback; // フィードバック
+ int TrainingLevel; // トレーニングレベル
+ int RR; // バイタル出力(RR間隔)
+ float PupilL; // 瞳孔径
+ float PupilR; // 瞳孔径
+ cv::Mat H; // ホモグラフィ行列
+};
+
+// ログ記録クラス
+class Logger {
+ const char* DATA_LOG_FILE = LOG_DIR "%s_%s_%d.csv";
+ const TCHAR* EVENT_LOG_FILE = _T(LOG_DIR "events.txt");
+
+ std::wstring _logFileName;
+public:
+ Logger();
+ static bool Write(TCHAR* filename, TCHAR* msg);
+ void Start(std::string subject, int visit);
+ void Write(Record& r);
+ void Stop();
+};
+
+// 将来ログクラスを階層化する
+#if 0
+class DataLogger : public Logger {
+ void Start(std::string subject, int visit);
+};
+#endif
\ No newline at end of file
diff --git a/ECTrainer2/Stimulus.cpp b/ECTrainer2/Stimulus.cpp
index da88b01..d7f97b8 100644
--- a/ECTrainer2/Stimulus.cpp
+++ b/ECTrainer2/Stimulus.cpp
@@ -171,6 +171,7 @@
}
if (_StimInfoSet[newStimNo].type == StimInfo::TYPE_MOVIE) {
+ this->SetImage(BLACK_FILE);
_cap.open(_StimInfoSet[newStimNo].smallmovie);
if (!_cap.isOpened()) {
Ect()->PWorker()->EventLog((_T("Can't open small movie file: ") +
diff --git a/ECTrainer2/Stimulus.h b/ECTrainer2/Stimulus.h
index d9ab41d..8159b28 100644
--- a/ECTrainer2/Stimulus.h
+++ b/ECTrainer2/Stimulus.h
@@ -29,13 +29,14 @@
class Stimulus : public BaseProcess
{
public:
+ static const int SMALL_MOVIE_WIDTH = 640; // 縮小動画の幅(px) 全画面表示抑制の判定に使う
private:
const std::string STIM_CONFIG_FILE = "../config/visit%02d.txt";
const cv::String OPENING_FILE = "../images/StartPage.png";
const cv::String CALIB_FILE = "../images/TobiiCalib.png";
const cv::String CALIB_COMPLETE_FILE = "../images/CalibOK.png";
const cv::String CALIB_FAILED_FILE = "../images/CalibFailed.png";
- const cv::String WHITE_FILE = "../images/White.png";
+ const cv::String BLACK_FILE = "../images/Black.png";
const cv::String ERROR_FILE = "../images/SystemError.png";
const cv::String EXP_STOP_FILE = "../images/ExpStop.png";
const cv::String EXP_DONE_FILE = "../images/ExpDone.png";
diff --git a/ECTrainer2/Worker.cpp b/ECTrainer2/Worker.cpp
index 096007e..98b3b31 100644
--- a/ECTrainer2/Worker.cpp
+++ b/ECTrainer2/Worker.cpp
@@ -14,7 +14,6 @@
// コンストラクタ
Worker::Worker(ECTrainer* pEct) : BaseProcess(pEct)
, _AppStatus(APP_STATUS::BOOT)
- , _fpLogData(NULL)
, _pExpTimer(NULL)
, _pContactTimer(NULL)
, _TargetImage()
@@ -59,7 +58,7 @@
// 表示画像取得
if (_StimImage.empty() || Ect()->PStimulus()->IsNewDisplay()) {
_StimImage = Ect()->PStimulus()->GetDisplay();
- _FullScreenImage.Put(_StimImage);
+ if (_StimImage.cols != Stimulus::SMALL_MOVIE_WIDTH) _FullScreenImage.Put(_StimImage);
}
// ターゲット画像生成
@@ -133,31 +132,25 @@
}
// ログ出力
- if (stimNo >= 0 && _fpLogData != NULL) {
- _ftprintf(_fpLogData, _T("%.3f"), _pExpTimer->Elapse() / 1000.); // 経過時間
- _ftprintf(_fpLogData, _T(",%d"), stimNo); // 刺激データ番号
- _ftprintf(_fpLogData, _T(",%.3f"), Ect()->PStimulus()->GetStimTime() / 1000.); // 刺激提示の経過時間
- _ftprintf(_fpLogData, _T(",%.1f,%.1f"), gazeV.x, gazeV.y); // 注視点(視野カメラ座標)
- auto logShift = _ShiftLog.size() > 0 && Ect()->PStimulus()->GetStimTime() >= SHIFT_LOG_STARTTIME
- && gazeI.x >= 0 ? _ShiftLog.back() : _Shift;
- _ftprintf(_fpLogData, _T(",%.1f,%.1f"), logShift.x, logShift.y); // ずれ
- _ftprintf(_fpLogData, _T(",%.1f,%.1f"), gazeI.x, gazeI.y); // 注視点(画像座標)
- _ftprintf(_fpLogData, _T(",%d"), hit + 1); // ターゲット判定
- _ftprintf(_fpLogData, _T(",%.2f"), _ContactTime / 1000.); // 目標コンタクト時間
- _ftprintf(_fpLogData, _T(",%d"), fb); // フィードバック
- _ftprintf(_fpLogData, _T(",%d"), _TrainingLevel); // トレーニングレベル
- _ftprintf(_fpLogData, _T(",%d"), Ect()->PBitalMonitor()->GetRR()); // バイタル出力(RR間隔)
- auto pd = Ect()->PEyeTrack()->GetPupilDiam();
- _ftprintf(_fpLogData, _T(",%.1f,%.1f"), pd.r, pd.l); // 瞳孔径
- // ホモグラフィ行列出力
- cv::Mat h = Ect()->PMarker()->GetHomography();
- if (!h.empty() && h.rows == 3 && h.cols == 3) {
- double* ptr = h.ptr(0);
- for (int i = 0; i < 9; i++) {
- _ftprintf(_fpLogData, _T(",%lf"), *(ptr + i));
- }
- }
- _ftprintf(_fpLogData, _T("\n"));
+ if (stimNo >= 0) {
+ Record r;
+ r.ElapTime = _pExpTimer->Elapse() / 1000.; // 経過時間
+ r.StimNo = stimNo; // 刺激データ番号
+ r.SceneTime = Ect()->PStimulus()->GetStimTime() / 1000.; // 刺激提示の経過時間
+ r.GazeV = gazeV; // 注視点(視野カメラ座標)
+ r.Shift = _ShiftLog.size() > 0 && Ect()->PStimulus()->GetStimTime() >= SHIFT_LOG_STARTTIME
+ && gazeI.x >= 0 ? _ShiftLog.back() : _Shift; // ずれ
+ r.GazeI = gazeI; // 注視点(画像座標)
+ r.Target = hit + 1; // ターゲット判定
+ r.ContactTime = _ContactTime / 1000.; // 目標コンタクト時間
+ r.Feedback = fb; // フィードバック
+ r.TrainingLevel = _TrainingLevel; // トレーニングレベル
+ r.RR = Ect()->PBitalMonitor()->GetRR(); // バイタル出力(RR間隔)
+ auto pd = Ect()->PEyeTrack()->GetPupilDiam(); // 瞳孔径
+ r.PupilL = pd.l;
+ r.PupilR = pd.r;
+ r.H = Ect()->PMarker()->GetHomography(); // ホモグラフィ行列
+ _DataLog.Write(r);
}
return true;
@@ -206,7 +199,7 @@
case (int)ECTMSG::EXP_START: // 実験開始
if (_AppStatus == APP_STATUS::IDLE) {
- this->OpenDataLog();
+ _DataLog.Start(Ect()->Subject(), Ect()->Visit());
this->EventLog(_T("Experiment Start"));
_pExpTimer->Reset();
this->ResetParams();
@@ -217,7 +210,7 @@
case (int)ECTMSG::EXP_STOP: // 実験停止
if (_AppStatus == APP_STATUS::STIM) {
- this->CloseDataLog();
+ _DataLog.Stop();
_AppStatus = APP_STATUS::IDLE;
Ect()->PStimulus()->PostMsg((int)ECTMSG::EXP_STOP);
this->EventLog(_T("Experiment Stopped"));
@@ -226,7 +219,7 @@
case (int)ECTMSG::EXP_END: // 実験終了
if (_AppStatus == APP_STATUS::STIM) {
- this->CloseDataLog();
+ _DataLog.Stop();
_AppStatus = APP_STATUS::IDLE;
Ect()->PStimulus()->PostMsg((int)ECTMSG::EXP_END);
this->EventLog(_T("Experiment Finished"));
@@ -277,32 +270,32 @@
return true;
}
-// データログファイルを開く
-void Worker::OpenDataLog() {
- this->CloseDataLog(); // 念のため閉じる
-
- auto filename = nkc::wut::Multi2Wide(cv::format(DATA_LOG_FILE, nkc::wut::DateTimeStr().c_str(),
- Ect()->Subject().c_str(), Ect()->Visit()));
-
- if (_tfopen_s(&_fpLogData, filename.c_str(), _T("w")) != 0) {
- Ect()->MsgBox(_T("Can't open data log file."), MB_ICONERROR);
- return;
- }
-
- // ヘッダ行
- _ftprintf(_fpLogData,
- _T("time,stimNo,stimTime,gazeVx,gazeVy,shiftX,shiftY,"
- "gazeIx,gazeIy,target,contact time,Feedback,TrainLevel,RR,pupilR,pupilL,"
- "H11,H12,H13,H21,H22,H23,H31,H32,H33\n"));
-}
-
-// データログファイルを開く
-void Worker::CloseDataLog() {
- if (_fpLogData) {
- fclose(_fpLogData);
- _fpLogData = NULL;
- }
-}
+//// データログファイルを開く
+//void Worker::OpenDataLog() {
+// this->CloseDataLog(); // 念のため閉じる
+//
+// auto filename = nkc::wut::Multi2Wide(cv::format(DATA_LOG_FILE, nkc::wut::DateTimeStr().c_str(),
+// Ect()->Subject().c_str(), Ect()->Visit()));
+//
+// if (_tfopen_s(&_fpLogData, filename.c_str(), _T("w")) != 0) {
+// Ect()->MsgBox(_T("Can't open data log file."), MB_ICONERROR);
+// return;
+// }
+//
+// // ヘッダ行
+// _ftprintf(_fpLogData,
+// _T("time,stimNo,stimTime,gazeVx,gazeVy,shiftX,shiftY,"
+// "gazeIx,gazeIy,target,contact time,Feedback,TrainLevel,RR,pupilR,pupilL,"
+// "H11,H12,H13,H21,H22,H23,H31,H32,H33\n"));
+//}
+//
+//// データログファイルを開く
+//void Worker::CloseDataLog() {
+// if (_fpLogData) {
+// fclose(_fpLogData);
+// _fpLogData = NULL;
+// }
+//}
// イベントログ出力
void Worker::EventLog(const TCHAR* msg) {
@@ -310,7 +303,7 @@
CreateDirectory(_T(LOG_DIR), NULL);
FILE* fp = NULL; // イベントログファイルポインタ
- if (_tfopen_s(&fp, EVENT_LOG_FILE, _T("a")) != 0) {
+ if (_tfopen_s(&fp, _T("../log/events.txt"), _T("a")) != 0) {
Ect()->MsgBox(_T("Can't open event log file."), MB_ICONERROR);
return;
}
diff --git a/ECTrainer2/Worker.h b/ECTrainer2/Worker.h
index 828ed9c..a23124a 100644
--- a/ECTrainer2/Worker.h
+++ b/ECTrainer2/Worker.h
@@ -6,6 +6,7 @@
#include "nkcOpenCV.h"
#include "RingBuffer.h"
#include "HPTimer.h"
+#include "Logger.h"
class BaseProcess;
@@ -24,14 +25,10 @@
const TCHAR* SOUND_GREAT = _T("../voices/Great_S.wav");
const TCHAR* SOUND_EXCELLENT = _T("../voices/Excellent_S.wav");
const TCHAR* SOUND_GOOUT = _T("../voices/KbdKeyTap.wav");
- #define LOG_DIR "../log/"
- const char* DATA_LOG_FILE = LOG_DIR "%s_%s_%d.csv";
- const TCHAR* EVENT_LOG_FILE = _T(LOG_DIR "events.txt");
const int FEEDBACK_TIME = 3000; // フィードバックの時間(1レベル)msec
const int SHIFT_LOG_STARTTIME = 2000; // 注視点ずれ記録開始時間
const float TRAINING_LEVEL_EFFECT = 0.1F; // トレーニングレベルによる目標領域縮小量
APP_STATUS _AppStatus; // アプリケーション状態
- FILE* _fpLogData; // データログファイルポインタ
nkc::HPTimer* _pExpTimer; // 実験経過タイマー
nkc::HPTimer* _pContactTimer; // 目標コンタクトタイマー
//mwut::HPTimer* _pNohitTimer; // 視線外れ時間
@@ -46,6 +43,7 @@
std::vector _ShiftLog; // 注視点のずれ記録
cv::Point2f _Shift; // 注視点のずれ
int _StartStage; // 開始ステージ
+ Logger _DataLog; // データログ
// ECTrainerインスタンス取得
ECTrainer* Ect() { return (ECTrainer*)_pUserdata; }
@@ -55,10 +53,10 @@
bool EventProc(MSG& msg);
// 判定パラメータをリセット
void ResetParams();
- // データログファイルを開く
- void OpenDataLog();
- // データログファイルを開く
- void CloseDataLog();
+ //// データログファイルを開く
+ //void OpenDataLog();
+ //// データログファイルを開く
+ //void CloseDataLog();
// FPS表示
void FPS(double fps);