⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.cpp

📁 基于点轨迹的手势识别.鼠标右键点击开始记录鼠标轨迹,基于记录的轨迹,利用神经网络算法进行识别.
💻 CPP
字号:
// Main.cpp : Implementation of _Main
/*
 Copyright (c) 2001 
 Author: Konstantin Boukreev 
 E-mail: konstantin@mail.primorye.ru 

 Created: 09.11.2001 13:15:13
 Version: 1.0.0

*/

#include "stdafx.h"
#include "Main.h"
#include "GestureData.h"
#include "AboutBox.h"

_Main::_Main()
	: 
	m_net(3, NET_INPUT_SIZE, NET_INPUT_SIZE, NET_OUTPUT_SIZE),
	m_board(RANGE_SIZE),
	m_learn(m_net),
	m_test_stage(0)
{	
	m_net.set_transfer_function(GestureLearn::sigmoid);
	m_net.set_bias(0.5);
	m_net.set_minmax(.0, 1.);
}

_Main::~_Main()
{
}

LRESULT _Main::OnTrain(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)	
{
	if (IDOK != m_trainDlg.DoModal(m_hWnd))
		return 0;

	m_learn.stop();
	m_learn.start(m_hWnd, &m_board, m_trainDlg.m_cycles, 
		m_trainDlg.m_hi_rate, m_trainDlg.m_lo_rate, m_trainDlg.m_momentum, m_trainDlg.m_error);	

	UIUpdate();
	return 0;
}

LRESULT _Main::OnStop(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	if (m_test_stage)
	{
		StopTest();
	}
	else
	{
		m_learn.stop();		
	}

	m_board.Refresh();	
	UIUpdate();
	return 0;
}

bool _Main::RecognizeBoard()
{	
	MLNet::array_t v_in (NET_INPUT_SIZE);
	MLNet::array_t v_out(NET_OUTPUT_SIZE);

	std::copy(m_board.m_cosines.begin(), m_board.m_cosines.end(), v_in.begin());
	std::copy(m_board.m_sinuses.begin(), m_board.m_sinuses.end(), v_in.begin() + RANGE_SIZE);

	m_net.propagate(v_in, v_out);

	typedef MLNet::array_t::iterator iterator;

	// apply softmax to a net output vector and find winner
	
	double sum = std::accumulate(v_out.begin(), v_out.end(), 0.);

	for (unsigned n = 0; n < sizeof(m_board.m_winners)/sizeof(m_board.m_winners[0]); ++n)
	{
		iterator i = std::max_element(v_out.begin(), v_out.end());
		m_board.m_winners[n].m_id = i - v_out.begin();
		m_board.m_winners[n].m_probability = (float)(double(*i) / sum);
		*i = 0;
	}	

	// verify winner 

	#define MIN_PROBABILITY 0.25
	#define MIN_DIFFERENCE	0.25

	if (m_board.m_winners[0].m_probability > MIN_PROBABILITY && 
	   (m_board.m_winners[0].m_probability - m_board.m_winners[1].m_probability) > MIN_DIFFERENCE)
	{
		m_board.m_mode = Board::recognized_success;
		return true;
	}

	m_board.m_mode = Board::recognized_fail;

	UIUpdate();
	return false;
}

//////////////////////////////////////////////////////

LRESULT _Main::OnFileOpen(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	OPENFILENAME ofn = {0};
	
	TCHAR buffer[MAX_PATH] = {0};
	
	if (m_filename.size())
		lstrcpy(buffer, m_filename.c_str());
	
	ofn.lStructSize	= sizeof OPENFILENAME;
	ofn.lpstrFile	= buffer;
	ofn.nMaxFile	= MAX_PATH;	
	ofn.hwndOwner	= m_hWnd;
	ofn.Flags		= OFN_EXPLORER|OFN_HIDEREADONLY;
	ofn.lpstrFilter = _T("Gesture network weights files (*.weights)\0*.weights\0")
					  _T("All files\0*.*\0");
	
	TCHAR dir[MAX_PATH];
	if (GetModuleFileName(GetModuleHandle(0), dir, MAX_PATH))
	{
		PathRemoveFileSpec(dir);
		ofn.lpstrInitialDir = dir;
	}
		
	if (!GetOpenFileName(&ofn))
		return 0;

	if (LoadNet(ofn.lpstrFile))
	{
		m_filename = ofn.lpstrFile;
		m_board.m_mode = Board::recognizing_mode;
		m_board.Refresh();
	}
	else
	{
		kb::MsgBox(MB_ICONWARNING, _T("GestureApp Open"), 
			_T("Unable to open file %s"), ofn.lpstrFile);
	}

	UIUpdate();
	return 0;
}
LRESULT _Main::OnFileSave(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	if (!m_filename.size())
	{
		OnFileSaveAs(wNotifyCode, wID, hWndCtl, bHandled);
	}
	else
	{
		if (!SaveNet(m_filename.c_str()))
		{
			kb::MsgBox(MB_ICONWARNING, _T("GestureApp Save"), 
				_T("Unable to save file %s"), m_filename.c_str());
		}			
	}

	UIUpdate();
	return 0;
}
LRESULT _Main::OnFileSaveAs(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	OPENFILENAME ofn = {0};
	
	TCHAR buffer[MAX_PATH] = {0};
	
	if (m_filename.size())
		lstrcpy(buffer, m_filename.c_str());
	
	ofn.lStructSize	= sizeof OPENFILENAME;
	ofn.lpstrFile	= buffer;
	ofn.nMaxFile	= MAX_PATH;	
	ofn.hwndOwner	= m_hWnd;
	ofn.Flags		= OFN_EXPLORER|OFN_HIDEREADONLY;
	ofn.lpstrFilter = _T("Gesture network weights files (*.weights)\0*.weights\0")
					  _T("All files\0*.*\0");
	
	TCHAR dir[MAX_PATH];
	if (GetModuleFileName(GetModuleHandle(0), dir, MAX_PATH))
	{
		PathRemoveFileSpec(dir);
		ofn.lpstrInitialDir = dir;
	}
		
	if (!GetSaveFileName(&ofn))
		return 0;
	
	PathAddExtension(ofn.lpstrFile, _T(".weights"));

	// to verify exists
	WIN32_FIND_DATA fd;
	HANDLE f = FindFirstFile(ofn.lpstrFile, &fd); 
	if (INVALID_HANDLE_VALUE != f)
	{
		FindClose(f);
		
		TCHAR msg[512] = {0};
		wsprintf(msg, _T("%s already exists.\nDo you want to replace it?"), ofn.lpstrFile);
		if (IDNO == ::MessageBox(m_hWnd, msg, _T("GestureApp Save"), MB_ICONWARNING|MB_YESNO))
			return 0;
	}
	
	m_filename.empty();
	if (SaveNet(ofn.lpstrFile))
	{
		m_filename = ofn.lpstrFile;		
	}		
	else
	{
		kb::MsgBox(MB_ICONWARNING, _T("GestureApp Save"), 
			_T("Unable to save file %s"), ofn.lpstrFile);
	}		

	UIUpdate();
	return 0;
}

bool _Main::SaveNet(const TCHAR* filename)
{	
	HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ,
		0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	_ASSERTE(file != INVALID_HANDLE_VALUE);
	if (file == INVALID_HANDLE_VALUE) return false;

	DWORD data_size = m_net.size_weight() * sizeof(MLNet::array_t::value_type);
	MLNet::array_t::value_type* p = (MLNet::array_t::value_type*)_alloca(data_size);
		
	typedef MLNet::array_t::iterator iterator;
	MLNet::array_t::value_type* t = p;
	for (iterator i = m_net.begin_weight(); i != m_net.end_weight(); ++i, ++t)
		*t = *i;

	DWORD written = 0;	
	BOOL r = WriteFile(file, p, data_size, &written, 0);
	_ASSERTE(r);	
	VERIFY(CloseHandle(file));
	if (written != data_size)
		return false;
	return r != 0;
}

bool _Main::LoadNet(const TCHAR* filename)
{
	HANDLE file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
		0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

	_ASSERTE(file != INVALID_HANDLE_VALUE);
	if (file == INVALID_HANDLE_VALUE) return false;

	DWORD data_size = GetFileSize(file, 0);

	if (data_size != m_net.size_weight() * sizeof(MLNet::array_t::value_type))
		return false; // invalid size

	MLNet::array_t::value_type* p = (MLNet::array_t::value_type*)_alloca(data_size);
		
	DWORD number_of_read = 0;	
	BOOL r = ReadFile(file, p, data_size, &number_of_read, 0);
	_ASSERTE(r); r;
	VERIFY(CloseHandle(file));

	if (data_size != number_of_read)
		return false; // invalid size

	typedef MLNet::array_t::iterator iterator;
	MLNet::array_t::value_type* t = p;
	for (iterator i = m_net.begin_weight(); i != m_net.end_weight(); ++i, ++t)
		*i = *t;
	return true;
}

//////////////////////////////////////////////////////

LRESULT _Main::OnTest(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	StartTest();
	return 0;
}

void _Main::StartTest()
{
	_ASSERTE(sizeof(pattern_data)/sizeof(pattern_data[0]) == NUMBER_OF_PATTERNS);

	if (IDOK != m_testDlg.DoModal(m_hWnd))
		return;

	if (m_testDlg.m_selected.empty())
	{
		MessageBox(_T("Unable to start test, need to select at least one pattern for testing"),
			_T("GestureApp"), MB_ICONWARNING);
		return;
	}
		
	m_test_cycle	= 0;
	m_test_stage	= 1;
	m_cur_pattern	= m_testDlg.m_selected.begin();
	m_cur_pos		= m_path.end();				
	
	m_board.GetClientRect(&m_rcBoard);		
	InflateRect(&m_rcBoard, -5, -5);
		
	int cx				= m_rcBoard.right - m_rcBoard.left;
	int cy				= m_rcBoard.bottom - m_rcBoard.top;
	int mv				= min(cx, cy);
	m_rcBoard.left		= m_rcBoard.left + (cx - mv) / 2;
	m_rcBoard.top		= m_rcBoard.top  + (cy - mv) / 2;
	m_rcBoard.right		= m_rcBoard.left + mv;
	m_rcBoard.bottom	= m_rcBoard.top  + mv;
	
	// wait 50 .. 500 ms			
	SetTimer(TEST_TIMER_ID, 500 / m_testDlg.m_speed);
}

void _Main::StopTest()
{
	if (m_test_stage)
	{
		KillTimer(TEST_TIMER_ID);
		m_board.SetInfoStr(0);
		m_board.Refresh();
		m_test_stage = 0;
		m_path.clear();
	}	
}

LRESULT _Main::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{	
	_ASSERTE(wParam == TEST_TIMER_ID);
	_ASSERTE(m_test_stage != 0);

	typedef Board::path_t::iterator iterator;
	
	if (m_cur_pos == m_path.end())
	{
		if (m_test_stage == 1)
		{
			// wait 50 .. 500 ms			
			SetTimer(TEST_TIMER_ID, 500 / m_testDlg.m_speed);

			// start a next pattern cycle
			Board::vector_real_t vec(RANGE_SIZE);	
			for (unsigned n = 0; n < RANGE_SIZE; ++n)
			{				
				if (m_testDlg.m_noise == CustTestDlg::LO_NOISE) 
					vec[n] = pattern_data[*m_cur_pattern][n];
				else
					vec[n] = (float)GestureLearn::add_noise(
						CustTestDlg::HI_NOISE - m_testDlg.m_noise,
						CustTestDlg::HI_NOISE, 
						pattern_data[*m_cur_pattern][n]);			
			}				
			Board::vector_to_path(m_rcBoard, vec, m_path);
			m_cur_pos = m_path.begin();

			m_test_stage = 2;
		}
		else
		{
			// end of pattern cycle

			m_board.StopMouseRecord();										
			m_path.clear();
			
			if (m_board.m_mode != Board::untrained_mode && 
				m_board.m_winners[0].m_id != *m_cur_pattern)
			{
				KillTimer(TEST_TIMER_ID);

				if (IDNO == kb::MsgBox(MB_ICONWARNING|MB_YESNO, 
					_T("GestureApp, Test"),
					_T("Pattern \"%s\" is recognized incorrectly\nContinue ?"), 
					pattern_names[*m_cur_pattern]))
				{
					StopTest();
					return 0;
				}
			}

			// wait 100 .. 1000 ms			
			SetTimer(TEST_TIMER_ID, 1000 / m_testDlg.m_speed);

			++m_cur_pattern;

			if (m_cur_pattern == m_testDlg.m_selected.end())
			{
				++m_test_cycle;
				if (m_test_cycle == m_testDlg.m_repeat)
				{
					StopTest();
					return 0;
				}					

				m_path.clear();
				m_cur_pattern	= m_testDlg.m_selected.begin();				
				m_cur_pos		= m_path.end();				
			}
			
			m_test_stage = 1;
			return 0;
		}
	}							
	
	_ASSERTE(m_cur_pos != m_path.end());

	POINT pt;
	pt.x = min(m_rcBoard.right,  max(m_rcBoard.left, m_rcBoard.left + (*m_cur_pos).x));
	pt.y = min(m_rcBoard.bottom, max(m_rcBoard.top,  m_rcBoard.top  + (*m_cur_pos).y));
	
	if (m_cur_pos == m_path.begin())
	{
		TCHAR buf[256];	
		sprintf(buf, "test \"%s\" pattern #%u(%u), press ESC for canceling", 
			pattern_names[*m_cur_pattern], 
			m_cur_pattern - m_testDlg.m_selected.begin() + m_testDlg.m_selected.size() * m_test_cycle, 
			m_testDlg.m_selected.size() * m_testDlg.m_repeat);
		m_board.SetInfoStr(buf);

		m_board.StartMouseRecord();
		m_board.AddMouseRecord(pt);
	}					
	else
	{		
		m_board.AddMouseRecord(pt);
	}

	m_board.Refresh(true);	
	++m_cur_pos;	
	return 0;
}

//////////////////////////////////////////////////////

void _Main::UIUpdate()
{
	HMENU hMenu		= GetMenu();
	HMENU hMenuFile = GetSubMenu(hMenu, 0);
	HMENU hMenuNet	= GetSubMenu(hMenu, 1);	
	
	switch (m_board.m_mode)
	{
	case Board::untrained_mode: 
		EnableMenuItem(hMenuFile, ID_FILEOPEN,	MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuFile, ID_FILESAVE,	MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuFile, ID_FILESAVEAS,MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_TRAIN,		MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuNet,  ID_STOP,		MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_TEST,		MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_RECOGNIZE,	MF_BYCOMMAND|MF_GRAYED); 
		break;
		
	case Board::training_mode: 
		EnableMenuItem(hMenuFile, ID_FILEOPEN,	MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuFile, ID_FILESAVE,	MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuFile, ID_FILESAVEAS,MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_TRAIN,		MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_STOP,		MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuNet,  ID_TEST,		MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_RECOGNIZE,	MF_BYCOMMAND|MF_GRAYED); 
		break;

	case Board::trained_mode: 
	case Board::recognizing_mode: 
	case Board::recognized_success:
	case Board::recognized_fail:
		EnableMenuItem(hMenuFile, ID_FILEOPEN,	MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuFile, ID_FILESAVE,	MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuFile, ID_FILESAVEAS,MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuNet,  ID_TRAIN,		MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuNet,  ID_STOP,		MF_BYCOMMAND|MF_GRAYED); 
		EnableMenuItem(hMenuNet,  ID_TEST,		MF_BYCOMMAND|MF_ENABLED); 
		EnableMenuItem(hMenuNet,  ID_RECOGNIZE,	MF_BYCOMMAND|MF_ENABLED);
		break;
	
	default: _ASSERTE(0); break;
	}
	
	if (m_test_stage)
	{
		EnableMenuItem(hMenuNet,  ID_STOP,		MF_BYCOMMAND|MF_ENABLED); 
	}
}

/////////////////////////////////////////////////////

bool _Main::OpenHLink(const TCHAR* url)
{
	// use COM
		
	HRESULT hr;
	CComPtr<IUniformResourceLocator> spURL;
	hr = ::CoCreateInstance(CLSID_InternetShortcut, 0, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (void**)&spURL);
	if (SUCCEEDED(hr)) 
	{
		hr = spURL->SetURL(url, IURL_SETURL_FL_GUESS_PROTOCOL);
		if (SUCCEEDED(hr)) 
		{  
			URLINVOKECOMMANDINFO ivci;
			ivci.dwcbSize	= sizeof (URLINVOKECOMMANDINFO);
			ivci.dwFlags	= 0;
			ivci.hwndParent	= m_hWnd;
			ivci.pcszVerb	= _T("open"); 
			
			if (SUCCEEDED(spURL->InvokeCommand (&ivci)))
				return true;
		}
	}	
	
	// attempt to use Shell

	SHELLEXECUTEINFO sei = {0};
	sei.cbSize	= sizeof SHELLEXECUTEINFO;
	sei.fMask	= 0; //SEE_MASK_FLAG_NO_UI ;
	sei.hwnd	= m_hWnd;
	sei.lpVerb	= _T("open");
	sei.lpFile	= url;
	sei.nShow	= SW_SHOW;

	return ShellExecuteEx(&sei) == TRUE;
}

LRESULT _Main::OnSendEmail(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{		
	const TCHAR *url = _T("mailto:konstantin@mail.primorye.ru?subject=GestureApp");
	if (!OpenHLink(url))
	{
		kb::MsgBox(MB_ICONWARNING, _T("GestureApp"), _T("Unable to send e-mail to %s"), url);
	}
	return 0;
}

LRESULT _Main::OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
	AboutBox dlg;
	dlg.DoModal(m_hWnd);
	return 0;
}

LRESULT _Main::OnHelp(WORD, WORD, HWND, BOOL&)
{			
	TCHAR url[1024];
	GetModuleFileName(GetModuleHandle(0), url, sizeof(url)/sizeof(url[0]));
	PathRemoveFileSpec(url);
	PathAddBackslash(url);
	lstrcat(url, _T("help\\gestureapp_help.htm"));

	if (!OpenHLink(url))
	{
		kb::MsgBox(MB_ICONWARNING, _T("GestureApp"), _T("Unable to open file %s"), url);
	}

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -