Newer
Older
PrismSoftware / ECTrainer2 / Stimulus.cpp
#include "BaseProcess.h"
#include "Stimulus.h"
#include "ECTrainer.h"
#include "ECTrainerGUI.h"
#include "Worker.h"

// コンストラクタ
Stimulus::Stimulus(ECTrainer* pEct) : BaseProcess(pEct)
	, _StimNo(-1)
	, _pMovieObject(NULL)
	, _Display()
	, _Movie()
	, _TotalExpTime(0)
{
	_pMovieObject = new MovieObject;
}

Stimulus::~Stimulus() {
	nkc::wut::SafeDelete((void**)&_pMovieObject);
}

// 初期化
bool Stimulus::Init() {
	_Display.Put(cv::imread(OPENING_FILE));

	// 設定ファイルをテーブルに読み込み
	nkc::STR_TABLE table;
	if (!nkc::wut::ReadTable(STIM_CONFIG_FILE, table)) {
		nkc::wut::DebugPrintf(_T("Can't open config file : %d\n"), STIM_CONFIG_FILE.c_str());
		return false;
	}

	// テーブルから構造体へ格納
	_TotalExpTime = 0;
	for (int r = 0; r < table.size(); r++) {
		if (table[r].size() != 5 || atoi(table[r][0].c_str()) < 1) continue;
		StimInfo st;
		st.type = atoi(table[r][0].c_str());
		st.filepath = table[r][1];
		int idx = (int)st.filepath.find_last_of("/\\");
		st.filename = idx == std::string::npos ? st.filepath : st.filepath.substr(idx + 1);
		st.dulation = (float)atof(table[r][2].c_str());
		st.csvfile = table[r][3];
		st.smallmovie = table[r][4];
		if (st.filepath.size() > 0) {
			_StimInfoSet.push_back(st);
			_TotalExpTime += st.dulation;
		}
	}

	return true;
}

// 基本処理
bool Stimulus::Routine() {

	if (_StimNo >= 0) {
		double eTime = _StimTimer.Elapse();
		// 刺激切り替えタイムキーパー
		if (eTime / 1000. > (double)_StimInfoSet[_StimNo].dulation) {
			this->MoveNext();
		}

		// 動画を読み込む
		if (_StimInfoSet[_StimNo].type == 2 && _cap.isOpened()) {
			_cap.set(cv::CAP_PROP_POS_MSEC, eTime);
			cv::Mat frame;
			_cap >> frame;
			if (!frame.empty()) _Display.Put(frame);
		}
	}
	Sleep(15);

	return true;
}

// イベント処理
bool Stimulus::EventProc(MSG& msg) {
	switch (msg.message) {
	case (int)ECTMSG::CALIB_START: // キャリブレーション開始
		this->SetImage(CALIB_FILE);
		break;

	case (int)ECTMSG::CALIB_OK:	// キャリブレーション成功
		this->SetImage(CALIB_COMPLETE_FILE);
		break;

	case (int)ECTMSG::CALIB_FAILED:	// キャリブレーション失敗
	case (int)ECTMSG::CALIB_ERR:	// キャリブレーションエラー
		this->SetImage(CALIB_FAILED_FILE);
		break;

	case (int)ECTMSG::EXP_START: // 実験開始
		this->SetStimulus(0);
		break;

	case (int)ECTMSG::EXP_STOP: // 実験停止
		_StimNo = -1;
		this->SetImage(EXP_STOP_FILE);
		break;

	case (int)ECTMSG::EXP_END: // 実験終了
		_StimNo = -1;
		this->SetImage(EXP_DONE_FILE);
		break;

	case (int)ECTMSG::SYSTEM_ERROR: // システムエラー
		_StimNo = -1;
		this->SetImage(ERROR_FILE);
		break;

	case (int)ECTMSG::MOVIE_END: // 動画再生が末尾に到達
		this->MoveNext();
		break;
	}
	return true;
}

// 次の刺激へ移動
bool Stimulus::MoveNext() {
	if (_StimNo < 0) return false;

	if (_StimInfoSet[_StimNo].type == 2) {
		if (_cap.isOpened()) _cap.release();
		Ect()->PECTrainerGUI()->PostMsg((int)ECTMSG::MOVIE_STOP);
	}
	if (_StimNo + 1 < (int)_StimInfoSet.size()) {
		SetStimulus(_StimNo + 1);
		Ect()->PWorker()->PostMsg((int)ECTMSG::EXP_NEXT);
	} else {
		Ect()->PWorker()->PostMsg((int)ECTMSG::EXP_END);
	}
	return true;
}

// 刺激提示
bool Stimulus::SetStimulus(int newStimNo) {
	if (newStimNo < 0 || newStimNo >= _StimInfoSet.size()) return false;

	_pMovieObject->Clear();
	if (_StimInfoSet[newStimNo].csvfile[0] != '_') {
		this->LoadMovieObject(newStimNo);
	}

	if (_StimInfoSet[newStimNo].type == 1) {
		this->SetImage(_StimInfoSet[newStimNo].filepath);
	} else {
		_cap.open(_StimInfoSet[newStimNo].smallmovie);
		if (!_cap.isOpened()) {
			Ect()->PWorker()->EventLog((_T("Can't open small movie file: ") + 
				nkc::wut::Multi2Wide(_StimInfoSet[newStimNo].filepath)).c_str());

			Ect()->PWorker()->PostMsg((int)ECTMSG::SYSTEM_ERROR);
			return false;
		}
		_Movie.Put(nkc::wut::Multi2Wide(_StimInfoSet[newStimNo].filepath));
		Ect()->PECTrainerGUI()->PostMsg((int)ECTMSG::MOVIE_START);
	}

	_StimTimer.Reset();
	_StimNo = newStimNo;
	return true;
}

// 画像読み込み
bool Stimulus::SetImage(cv::String imageFile) {
	auto img = cv::imread(imageFile);
	if (img.empty()) {
		Ect()->PWorker()->EventLog((_T("Can't open image file: ") +
			nkc::wut::Multi2Wide(imageFile)).c_str());
		Ect()->PWorker()->PostMsg((int)ECTMSG::SYSTEM_ERROR);
		return false;
	}
	_Display.Put(img);
	return true;
}

// 動画オブジェクトの読み込み
void Stimulus::LoadMovieObject(int stimNo) {
	int nFrames = _pMovieObject->SetData(_StimInfoSet[stimNo].csvfile);

	nkc::wut::DebugPrintf(_T("Movie object '%s' - %d frames read.\n"),
		nkc::wut::Multi2Wide(_StimInfoSet[stimNo].csvfile).c_str(), nFrames);
}

// ターゲット情報を取得
std::vector<Element> Stimulus::GetMovieObject(float eTime) {
	if (eTime < 0) eTime = (float)_StimTimer.Elapse() / 1000.F;
	return _pMovieObject->GetElements(eTime); 
}

// FPS表示
void Stimulus::FPS(double fps) {
	nkc::wut::DebugPrintf(_T("[Stimulus] %.1f fps\n"), fps);
}


// 画像にマーカーを描画
//void Stimulus::StimWithMarker() {
//	cv::Mat img = cv::imread(_StimImages[_StimNo].filename);
//	_pMarker->Generate(img.size());
//	_pMarker->DrawMarker(img);
//	img.copyTo(_DispBuffer);
//}