Browse Source

将ImgAssist分离出来,同时新增CaptureWnd函数。

Jeff 2 years ago
parent
commit
077462fa52

+ 2 - 346
GameAssist/GameAssist/Assist.cpp

@@ -9,6 +9,8 @@
 // #pragma comment(lib, "d3d11.lib")
 // #pragma comment(lib, "dxgi.lib")
 
+
+
 namespace GameAssist
 {
 	RECT g_rcRoleIdleHP = { 58, 34, 119, 40 };
@@ -644,349 +646,3 @@ namespace GameGlobal
 		OutputDebugStringA(szData);
 	}
 };
-
-namespace ImgAssist
-{
-	std::string CaptureGameWnd(HWND hWnd)
-	{
-		TCHAR szName[MAX_PATH] = {0};
-		_stprintf_s(szName, _T("%s%p.bmp"), GameGlobal::g_szTempDir, hWnd);
-		CaptureGameWnd(hWnd, szName);
-
-		return std::string(szName);
-	}
-
-	void CaptureGameWnd(HWND hWnd, std::string strSavePath)
-	{
-		HDC hDC = ::GetWindowDC(hWnd);
-		ASSERT(hDC);
-		HDC hMemDC = ::CreateCompatibleDC(hDC);
-		ASSERT(hMemDC);
-
-		RECT rc;
-		::GetWindowRect(hWnd, &rc);
-		HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top);
-
-		ASSERT(hBitmap);
-		HBITMAP hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBitmap);
-
-		BOOL bRet = FALSE;
-		BOOL bProcessed = FALSE;
-		// 针对win10 DWM虚拟缩放时的处理
-		if (GetDeviceCaps(hDC, LOGPIXELSX) != 96)
-		{
-			DEVMODE curDevMode;
-			memset(&curDevMode, 0, sizeof(curDevMode));
-			curDevMode.dmSize = sizeof(DEVMODE);
-			BOOL bEnumRet = ::EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &curDevMode);
-			if (bEnumRet < curDevMode.dmPelsWidth)
-			{
-				bProcessed = TRUE;
-				//::SetStretchBltMode(hMemDC, STRETCH_HALFTONE);
-				//bRet = ::StretchBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, 0, 0, curDevMode.dmPelsWidth, curDevMode.dmPelsHeight, SRCCOPY | CAPTUREBLT);
-			}
-		}
-
-		::PrintWindow(hWnd, hMemDC, 0);
-		BITMAP bitmap = { 0 };
-		::GetObject(hBitmap, sizeof(BITMAP), &bitmap);
-		BITMAPINFOHEADER bi = { 0 };
-		BITMAPFILEHEADER bf = { 0 };
-		CONST int nBitCount = 24;
-		bi.biSize = sizeof(BITMAPINFOHEADER);
-		bi.biWidth = bitmap.bmWidth;
-		bi.biHeight = bitmap.bmHeight;
-		bi.biPlanes = 1;
-		bi.biBitCount = nBitCount;
-		bi.biCompression = BI_RGB;
-		DWORD dwSize = ((bitmap.bmWidth * nBitCount + 31) / 32) * 4 * bitmap.bmHeight;
-		HANDLE hDib = GlobalAlloc(GHND, dwSize + sizeof(BITMAPINFOHEADER));
-		if (hDib == NULL)
-			return;
-		LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
-		//memcpy(lpbi, &bi, sizeof(BITMAPINFOHEADER));
-		*lpbi = bi;
-		::GetDIBits(hMemDC, hBitmap, 0, bitmap.bmHeight, (BYTE*)lpbi + sizeof(BITMAPINFOHEADER), (BITMAPINFO*)lpbi, DIB_RGB_COLORS);
-
-		CFile file;
-		CFileException fep;
-		if (file.Open(strSavePath.c_str(), CFile::modeCreate | CFile::modeWrite, &fep)) {
-			bf.bfType = 0x4d42;
-			dwSize += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
-			bf.bfSize = dwSize;
-			bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
-			file.Write((BYTE*)&bf, sizeof(BITMAPFILEHEADER));
-			file.Write((BYTE*)lpbi, dwSize);
-			file.Close();
-		}
-
-		GlobalUnlock(hDib);
-		GlobalFree(hDib);
-		::SelectObject(hMemDC, hOldBmp);
-		::DeleteObject(hBitmap);
-		::DeleteObject(hMemDC);
-		::ReleaseDC(hWnd, hDC);
-
-		Sleep(30);
-	}
-
-	BOOL OpenImage(std::string strImag, cv::Mat& img)
-	{
-		if (!PathFileExists(strImag.c_str()))
-			return FALSE;
-
-		if (img.data != NULL)
-			img.release();
-
-		img = cv::imread(strImag.c_str(), cv::IMREAD_COLOR);
-		if (img.data == NULL)
-			return FALSE;
-
-		return TRUE;
-	}
-
-	BOOL SetImgThreshold(cv::Mat& srcImg, cv::Mat& thresholdImg, long nThresholdVal, long nMaxThresholdVal, int type)
-	{
-		if (srcImg.data == NULL)
-			return FALSE;
-
-		if (thresholdImg.data && srcImg.data != thresholdImg.data)
-			thresholdImg.release();
-
-		switch (type)
-		{
-		case 0://全局阀值;
-		{
-			// 转成灰阶图;
-			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
-			// 再高斯模糊处理(滤波);
-			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(5, 5), 0, 0);
-			// 二值化;//全局化指定的阀值与返回值相等;
-			double dRetVal = cv::threshold(thresholdImg, thresholdImg, nThresholdVal, nMaxThresholdVal, cv::THRESH_BINARY);
-		}
-		break;
-		case 1://自适应阀值;
-		{
-			// 转成灰阶图;
-			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
-			// 再高斯模糊处理(滤波);
-			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(3, 3), 0, 0);
-			// 自适应阀值;
-			cv::medianBlur(thresholdImg, thresholdImg, 3);
-			// 局部二值化;//blocksize一般取3、5、7
-			cv::adaptiveThreshold(thresholdImg, thresholdImg, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 3, 4.5);
-		}
-		break;
-		case 2:// otsu阀值;
-		{
-			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
-			// 高斯模糊;
-			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(3, 3), 0, 0);
-			cv::threshold(thresholdImg, thresholdImg, nThresholdVal, nMaxThresholdVal, cv::THRESH_BINARY | cv::THRESH_OTSU);
-		}
-		break;
-		default:
-			break;
-		}
-
-		return TRUE;
-	}
-
-	BOOL GetImgMatchtemplate(HWND hWnd, std::string strTempImg, RECT& rc, double lowestMatchValue)
-	{
-		std::string strImage = CaptureGameWnd(hWnd);
-		cv::Mat srcImg, tempImg, matchImg;
-		if (!OpenImage(strImage, srcImg) || !OpenImage(strTempImg, tempImg))
-		{
-			if (srcImg.data) srcImg.release();
-			if (tempImg.data) tempImg.release();
-			return FALSE;
-		}
-
-		cv::matchTemplate(srcImg, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
-		// 归一化到0~1
-		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
-
-		double lv_nMinVal = 0.0;
-		double lv_nMaxVal = 0.0;
-		cv::Point lv_nMinLoc = cv::Point(0, 0);
-		cv::Point lv_nMaxLoc = cv::Point(0, 0);
-		cv::Point lv_MatchLoc = cv::Point(0, 0);
-		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
-
-		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
-		cv::Mat roiImg = srcImg(roi);
-		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
-
-		rc.left = lv_nMaxLoc.x - GameGlobal::frameWidth;
-		rc.top = lv_nMaxLoc.y - GameGlobal::titleBarHeight;
-		rc.right = rc.left + tempImg.cols;
-		rc.bottom = rc.top + tempImg.rows;
-
-		srcImg.release();
-		tempImg.release();
-		matchImg.release();
-		roiImg.release();
-
-		// 是否大于最低匹配度;
-		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
-	}
-
-	BOOL GetImgMatchtemplate(std::string strSrcImg, std::string strTempImg, RECT& rc, double lowestMatchValue)
-	{
-		cv::Mat srcImg, tempImg, matchImg;
-		if (!OpenImage(strSrcImg, srcImg) || !OpenImage(strTempImg, tempImg))
-		{
-			if (srcImg.data) srcImg.release();
-			if (tempImg.data) tempImg.release();
-			return FALSE;
-		}
-
-		cv::matchTemplate(srcImg, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
-		// 归一化到0~1
-		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
-
-		double lv_nMinVal = 0.0;
-		double lv_nMaxVal = 0.0;
-		cv::Point lv_nMinLoc = cv::Point(0, 0);
-		cv::Point lv_nMaxLoc = cv::Point(0, 0);
-		cv::Point lv_MatchLoc = cv::Point(0, 0);
-		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
-
-		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
-		cv::Mat roiImg = srcImg(roi);
-		//cv::imwrite("G:\\bin\\GameAssist\\match.bmp", roiImg);
-
-		rc.left = lv_nMaxLoc.x - GameGlobal::frameWidth;
-		rc.top = lv_nMaxLoc.y - GameGlobal::titleBarHeight;
-		rc.right = rc.left + tempImg.cols;
-		rc.bottom = rc.top + tempImg.rows;
-
-		srcImg.release();
-		tempImg.release();
-		matchImg.release();
-		roiImg.release();
-
-		// 是否大于最低匹配度;
-		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
-	}
-
-	BOOL IsMatchIcon(HWND hWnd, std::string strTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue)
-	{
-		std::string strImg = CaptureGameWnd(hWnd);
-		cv::Mat srcImg, tempImg, matchImg;
-		if (!OpenImage(strImg, srcImg) || !OpenImage(strTempImg, tempImg))
-		{
-			if (srcImg.data) srcImg.release();
-			if (tempImg.data) tempImg.release();
-			return FALSE;
-		}
-
-		// 指定源图片区域来做模块比较,提高效率;
-		cv::Mat imgROI;
-		imgROI = srcImg(cv::Rect(srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top));
-		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("roi")), imgROI);
-		/*
-		m_ImgROI = srcImg([&]()-> cv::Rect {
-			// 注意是x,y,w=cols,h=rows
-			return cv::Rect(srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top);
-		}());
-		*/
-
-		cv::matchTemplate(imgROI, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
-		// 归一化到0~1
-		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
-
-		double lv_nMinVal = 0.0;
-		double lv_nMaxVal = 0.0;
-		cv::Point lv_nMinLoc = cv::Point(0, 0);
-		cv::Point lv_nMaxLoc = cv::Point(0, 0);
-		cv::Point lv_MatchLoc = cv::Point(0, 0);
-		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
-
-		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
-		cv::Mat roiImg = imgROI(roi);
-		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
-
-		matchRect.left = srcRect.left + lv_nMaxLoc.x - GameGlobal::frameWidth;
-		matchRect.top = srcRect.top + lv_nMaxLoc.y - GameGlobal::titleBarHeight;
-		matchRect.right = matchRect.left + tempImg.cols;
-		matchRect.bottom = matchRect.top + tempImg.rows;
-
-		imgROI.release();
-		srcImg.release();
-		tempImg.release();
-		matchImg.release();
-		roiImg.release();
-
-		// 是否大于最低匹配度;
-		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
-	}
-
-	BOOL CropPicture(HWND hWnd, CRect rc, const char* szSaveName)
-	{
-		std::string strImg = CaptureGameWnd(hWnd);
-		cv::Mat srcImg, tempImg, matchImg;
-		if (!OpenImage(strImg, srcImg))
-		{
-			if (srcImg.data) srcImg.release();
-			return FALSE;
-		}
-
-		// 指定源图片区域来做模块比较,提高效率;
-		cv::Mat imgROI;
-		imgROI = srcImg(cv::Rect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
-		return cv::imwrite(szSaveName, imgROI);
-	}
-
-	BOOL IsSimilarPicture(const char* szp1, const char* szp2, double lowestMatchValue)
-	{
-		cv::Mat src, dest, matchImg;
-		src = cv::imread(szp1);
-		dest = cv::imread(szp2);
-
-		cv::matchTemplate(src, dest, matchImg, cv::TM_CCOEFF_NORMED);
-		// 归一化到0~1
-		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
-
-		double lv_nMinVal = 0.0;
-		double lv_nMaxVal = 0.0;
-		cv::Point lv_nMinLoc = cv::Point(0, 0);
-		cv::Point lv_nMaxLoc = cv::Point(0, 0);
-		cv::Point lv_MatchLoc = cv::Point(0, 0);
-		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
-
-		src.release();
-		matchImg.release();
-		dest.release();
-
-		// 是否大于最低匹配度;
-		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
-	}
-
-	int GetColorOccupiedLength(std::string strImg, int r, int g, int b)
-	{
-		cv::Mat src = cv::imread(strImg.c_str());
-		// 获取图片的矩形大小;
-		int width = src.cols;
-		int height = src.rows;
-
-		int i = 0;
-		for ( ; i < width; ++i )
-		{
-			cv::Vec3b pixel = src.at<cv::Vec3b>(height / 2, i);	// 读取第 height / 2行 第 i 列像素值;
-			if (abs(pixel[0] - b) <= 3 && abs(pixel[1] - g) <= 3 && abs(pixel[2] - r) <= 3)
-			{
-				continue;
-			}
-
-			break;
-		}
-		src.release();
-
-		GameGlobal::DebugLog(_T("[GameAssist] 颜色占比=%d,%d,%d"), i, width, i * 100 / width);
-
-		return i * 100 / width ;
-	}
-
-};

+ 1 - 14
GameAssist/GameAssist/Assist.h

@@ -5,6 +5,7 @@
 
 #include <map>
 #include <string>
+#include "ImgAssist.h"
 
 namespace GameGlobal {
 	enum {
@@ -33,20 +34,6 @@ namespace GameGlobal {
 	VOID DebugLog(CHAR* pszStr, ...);
 };
 
-namespace ImgAssist {
-	std::string CaptureGameWnd(HWND hWnd);
-	void CaptureGameWnd(HWND hWnd, std::string strSavePath);
-	BOOL OpenImage(std::string strImag, cv::Mat& img);
-	BOOL SetImgThreshold(cv::Mat& srcImg, cv::Mat& thresholdImg, long nThresholdVal, long nMaxThresholdVal, int type = 0);
-	BOOL GetImgMatchtemplate(HWND hWnd, std::string strTempImg, RECT& rc, double lowestMatchValue = 0.900);
-	BOOL GetImgMatchtemplate(std::string strSrcImg, std::string strTempImg, RECT& rc, double lowestMatchValue = 0.900);
-	BOOL IsMatchIcon(HWND hWnd, std::string strTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue = 0.900);
-	BOOL CropPicture(HWND hWnd, CRect rc, const char* szSaveName); // 剪裁图片;
-	BOOL IsSimilarPicture(const char* szp1, const char* szp2, double lowestMatchValue = 0.99);
-	// 获取指定颜色占用矩形长度比例;
-	int GetColorOccupiedLength(std::string strImg, int r, int g, int b);
-};
-
 // 所有坐标,都是基于游戏窗口的相对坐标值;
 // 游戏窗口:802*627
 namespace GameAssist{

+ 12 - 4
GameAssist/GameAssist/Assist.vcxproj

@@ -80,6 +80,8 @@
     <LinkIncremental>true</LinkIncremental>
     <OutDir>..\..\..\bin\$(SolutionName)</OutDir>
     <IntDir>$(OutDir)\$(Platform)\$(ConfigurationName)\</IntDir>
+    <IncludePath>D:\Program Files\Opencv\include;D:\Program Files\Opencv\include\opencv2;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Program Files\Opencv\lib\Debug;$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <OutDir>..\..\..\bin\$(SolutionName)\</OutDir>
@@ -90,6 +92,8 @@
     <LinkIncremental>false</LinkIncremental>
     <OutDir>..\..\..\bin\$(SolutionName)</OutDir>
     <IntDir>$(OutDir)\$(Platform)\$(ConfigurationName)\</IntDir>
+    <IncludePath>D:\Program Files\Opencv\include;D:\Program Files\Opencv\include\opencv2;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Program Files\Opencv\lib\Release;$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Midl>
@@ -132,7 +136,7 @@
       <PrecompiledHeader>Use</PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <AdditionalIncludeDirectories>..\opencv\;..\IMGProc</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\IMGProc</AdditionalIncludeDirectories>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
     <ResourceCompile>
@@ -145,7 +149,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>
       <AdditionalLibraryDirectories>..\opencv\lib</AdditionalLibraryDirectories>
-      <AdditionalDependencies>opencv_core420d.lib;opencv_imgproc420d.lib;opencv_highgui420d.lib;opencv_ml420d.lib;opencv_video420d.lib;opencv_features2d420d.lib;opencv_calib3d420d.lib;opencv_objdetect420d.lib;opencv_flann420d.lib;opencv_dnn420d.lib;opencv_imgcodecs420d.lib;opencv_photo420d.lib;opencv_stitching420d.lib;opencv_videoio420d.lib;opencv_gapi420d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>opencv_calib3d470d.lib;opencv_core470d.lib;opencv_dnn470d.lib;opencv_features2d470d.lib;opencv_flann470d.lib;opencv_gapi470d.lib;opencv_highgui470d.lib;opencv_imgcodecs470d.lib;opencv_imgproc470d.lib;opencv_ml470d.lib;opencv_objdetect470d.lib;opencv_photo470d.lib;opencv_stitching470d.lib;opencv_ts470d.lib;opencv_video470d.lib;opencv_videoio470d.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
       <Command>xcopy $(SolutionDir)img $(OutputPath)img\ /s/y/a</Command>
@@ -198,7 +202,7 @@
       <PrecompiledHeader>Use</PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <AdditionalIncludeDirectories>..\opencv\;..\IMGProc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\IMGProc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
     <ResourceCompile>
@@ -213,7 +217,7 @@
       <OptimizeReferences>true</OptimizeReferences>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <AdditionalLibraryDirectories>..\opencv\lib</AdditionalLibraryDirectories>
-      <AdditionalDependencies>opencv_core420.lib;opencv_imgproc420.lib;opencv_highgui420.lib;opencv_ml420.lib;opencv_video420.lib;opencv_features2d420.lib;opencv_calib3d420.lib;opencv_objdetect420.lib;opencv_flann420.lib;opencv_dnn420.lib;opencv_imgcodecs420.lib;opencv_photo420.lib;opencv_stitching420.lib;opencv_videoio420.lib;opencv_gapi420.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>opencv_calib3d470.lib;opencv_core470.lib;opencv_dnn470.lib;opencv_features2d470.lib;opencv_flann470.lib;opencv_gapi470.lib;opencv_highgui470.lib;opencv_imgcodecs470.lib;opencv_imgproc470.lib;opencv_ml470.lib;opencv_objdetect470.lib;opencv_photo470.lib;opencv_stitching470.lib;opencv_ts470.lib;opencv_video470.lib;opencv_videoio470.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
       <Command>xcopy $(SolutionDir)img $(OutputPath)img\ /s/y/a</Command>
@@ -247,6 +251,8 @@
     <ClCompile Include="DXGICaptor.cpp" />
     <ClCompile Include="GameAssist.cpp" />
     <ClCompile Include="GameAssistDlg.cpp" />
+    <ClCompile Include="ImgAssist.cpp" />
+    <ClCompile Include="KMAssist.cpp" />
     <ClCompile Include="MouseAssist.cpp" />
     <ClCompile Include="stdafx.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
@@ -277,6 +283,8 @@
     <ClInclude Include="DXGICaptor.h" />
     <ClInclude Include="GameAssist.h" />
     <ClInclude Include="GameAssistDlg.h" />
+    <ClInclude Include="ImgAssist.h" />
+    <ClInclude Include="KMAssist.h" />
     <ClInclude Include="MouseAssist.h" />
     <ClInclude Include="Resource.h" />
     <ClInclude Include="stdafx.h" />

+ 6 - 0
GameAssist/GameAssist/Assist.vcxproj.filters

@@ -69,6 +69,9 @@
     <ClCompile Include="..\IMGProc\opEnv.cpp">
       <Filter>IMGProc</Filter>
     </ClCompile>
+    <ClCompile Include="KMAssist.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="GameAssist.h">
@@ -149,6 +152,9 @@
     <ClInclude Include="..\IMGProc\imageView.hpp">
       <Filter>IMGProc</Filter>
     </ClInclude>
+    <ClInclude Include="KMAssist.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="Assist.ini">

+ 9 - 0
GameAssist/GameAssist/CAction.h

@@ -2,6 +2,15 @@
 
 namespace GameAssist {
 
+	// 模块图片;
+	typedef struct __IMG__ 
+	{
+		std::string name;		// 名称;
+		std::string file_path;	// 路径;
+		std::string desc;		// 描述;
+		int nType;				// 类型;
+	};
+
 	typedef struct __GACTION__ {
 		byte			byActionType;			// 动作类型;
 		std::string		strActionName;			// 动作名称;

+ 2 - 1
GameAssist/GameAssist/GameAssistDlg.cpp

@@ -387,7 +387,8 @@ void CGameAssistDlg::OnBnClickedButton2()  // 
 	{
 		CString strImg;
 		strImg = CTime::GetCurrentTime().Format("%H%M%S-Game.bmp");
-		ImgAssist::CaptureGameWnd(hWnd, strImg.GetString());
+		//ImgAssist::CaptureGameWnd(hWnd, strImg.GetString());
+		ImgAssist::CaptureWnd(hWnd);
 	}
 }
 

+ 472 - 0
GameAssist/GameAssist/ImgAssist.cpp

@@ -0,0 +1,472 @@
+#include "stdafx.h"
+#include "ImgAssist.h"
+
+
+namespace ImgAssist
+{
+	std::string CaptureGameWnd(HWND hWnd)
+	{
+		TCHAR szName[MAX_PATH] = { 0 };
+		_stprintf_s(szName, _T("%s%p.bmp"), GameGlobal::g_szTempDir, hWnd);
+		CaptureGameWnd(hWnd, szName);
+
+		return std::string(szName);
+	}
+
+	void CaptureGameWnd(HWND hWnd, std::string strSavePath)
+	{
+		HDC hDC = ::GetWindowDC(hWnd);
+		ASSERT(hDC);
+		HDC hMemDC = ::CreateCompatibleDC(hDC);
+		ASSERT(hMemDC);
+
+		RECT rc;
+		::GetWindowRect(hWnd, &rc);
+		HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top);
+
+		ASSERT(hBitmap);
+		HBITMAP hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBitmap);
+
+		BOOL bRet = FALSE;
+		BOOL bProcessed = FALSE;
+		// 针对win10 DWM虚拟缩放时的处理
+		if (GetDeviceCaps(hDC, LOGPIXELSX) != 96)
+		{
+			DEVMODE curDevMode;
+			memset(&curDevMode, 0, sizeof(curDevMode));
+			curDevMode.dmSize = sizeof(DEVMODE);
+			BOOL bEnumRet = ::EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &curDevMode);
+			if (bEnumRet < curDevMode.dmPelsWidth)
+			{
+				bProcessed = TRUE;
+				//::SetStretchBltMode(hMemDC, STRETCH_HALFTONE);
+				//bRet = ::StretchBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, 0, 0, curDevMode.dmPelsWidth, curDevMode.dmPelsHeight, SRCCOPY | CAPTUREBLT);
+			}
+		}
+
+		::PrintWindow(hWnd, hMemDC, 0);
+		BITMAP bitmap = { 0 };
+		::GetObject(hBitmap, sizeof(BITMAP), &bitmap);
+		BITMAPINFOHEADER bi = { 0 };
+		BITMAPFILEHEADER bf = { 0 };
+		CONST int nBitCount = 24;
+		bi.biSize = sizeof(BITMAPINFOHEADER);
+		bi.biWidth = bitmap.bmWidth;
+		bi.biHeight = bitmap.bmHeight;
+		bi.biPlanes = 1;
+		bi.biBitCount = nBitCount;
+		bi.biCompression = BI_RGB;
+		DWORD dwSize = ((bitmap.bmWidth * nBitCount + 31) / 32) * 4 * bitmap.bmHeight;
+		HANDLE hDib = GlobalAlloc(GHND, dwSize + sizeof(BITMAPINFOHEADER));
+		if (hDib == NULL)
+			return;
+		LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
+		//memcpy(lpbi, &bi, sizeof(BITMAPINFOHEADER));
+		*lpbi = bi;
+		::GetDIBits(hMemDC, hBitmap, 0, bitmap.bmHeight, (BYTE*)lpbi + sizeof(BITMAPINFOHEADER), (BITMAPINFO*)lpbi, DIB_RGB_COLORS);
+
+		CFile file;
+		CFileException fep;
+		if (file.Open(strSavePath.c_str(), CFile::modeCreate | CFile::modeWrite, &fep)) {
+			bf.bfType = 0x4d42;
+			dwSize += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+			bf.bfSize = dwSize;
+			bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+			file.Write((BYTE*)&bf, sizeof(BITMAPFILEHEADER));
+			file.Write((BYTE*)lpbi, dwSize);
+			file.Close();
+		}
+
+		GlobalUnlock(hDib);
+		GlobalFree(hDib);
+		::SelectObject(hMemDC, hOldBmp);
+		::DeleteObject(hBitmap);
+		::DeleteObject(hMemDC);
+		::ReleaseDC(hWnd, hDC);
+
+		Sleep(30);
+	}
+
+	cv::Mat CaptureWnd(HWND hWnd)
+	{
+		HDC hdcMemDC = NULL;		// 兼容DC;
+		HDC hdcWindow = NULL;		// 窗口DC;
+		BITMAP bmpWindow = {0};		// BITMAP窗口对象;
+		HBITMAP hbmpWindow = NULL;	// HBITMAP窗口对象;
+		DWORD dwBmpSize = 0;		// BITMAP大小;
+		char* lpbitmap = NULL;		// BITMAP数据;
+		HANDLE hDIB = NULL;
+		DWORD dwSizeofDIB = 0;
+		byte* pImgData = NULL;
+		// 获取窗口DC;
+		hdcWindow = ::GetWindowDC(hWnd);
+		// 创建窗口DC的兼容DC;
+		hdcMemDC = ::CreateCompatibleDC(hdcWindow);
+
+		RECT rc,rcc;
+		::GetWindowRect(hWnd, &rc);
+		::GetClientRect(hWnd, &rcc);
+		int width = rc.right - rc.left;
+		int height = rc.bottom - rc.top;
+		// 创建兼容位图;
+		hbmpWindow = ::CreateCompatibleBitmap(hdcWindow, width, height);
+		// 将位图选入兼容DC;
+		SelectObject(hdcMemDC, hbmpWindow);
+#if 1
+		// 将窗口复制到兼容DC中(当窗口被遮挡时,这个函数效果好)
+		if(!::PrintWindow(hWnd, hdcMemDC, 0))
+		{
+			goto done;
+		}
+#else
+		// 将目标DC的内容复制到兼容DC中;
+		if (!BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, SRCCOPY))
+		{
+			goto done;
+		}
+#endif		
+		// 通过HBITMAP获取BITMAP
+		GetObject(hbmpWindow, sizeof(BITMAP), &bmpWindow);
+
+		BITMAPFILEHEADER   bmfHeader = {0};
+		BITMAPINFOHEADER   bi = {0};
+
+		bi.biSize = sizeof(BITMAPINFOHEADER);
+		bi.biWidth = bmpWindow.bmWidth;
+		bi.biHeight = bmpWindow.bmHeight;
+		bi.biPlanes = 1;
+		bi.biBitCount = 32;
+		bi.biCompression = BI_RGB;
+		bi.biSizeImage = 0;
+		bi.biXPelsPerMeter = 0;
+		bi.biYPelsPerMeter = 0;
+		bi.biClrUsed = 0;
+		bi.biClrImportant = 0;
+
+		dwBmpSize = ((bmpWindow.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpWindow.bmHeight;
+
+		// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that 
+		// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc 
+		// have greater overhead than HeapAlloc.
+		hDIB = GlobalAlloc(GHND, dwBmpSize);
+		if (hDIB == NULL)
+		{
+			goto done;
+		}
+		lpbitmap = (char*)GlobalLock(hDIB);
+
+		// Gets the "bits" from the bitmap, and copies them into a buffer 
+		// that's pointed to by lpbitmap.
+		GetDIBits(hdcMemDC, hbmpWindow, 0,
+			(UINT)bmpWindow.bmHeight,
+			lpbitmap,
+			(BITMAPINFO*)&bi, DIB_RGB_COLORS);
+
+		// Add the size of the headers to the size of the bitmap to get the total file size.
+		dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+
+		// Offset to where the actual bitmap bits start.
+		bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
+
+		// Size of the file.
+		bmfHeader.bfSize = dwSizeofDIB;
+
+		// bfType must always be BM for Bitmaps.
+		bmfHeader.bfType = 0x4D42; // BM.
+
+		pImgData = new byte[dwSizeofDIB];
+		memset(pImgData, 0, dwSizeofDIB);
+		memcpy(pImgData, &bmfHeader, sizeof(BITMAPFILEHEADER));
+		memcpy(pImgData + sizeof(BITMAPFILEHEADER), &bi, sizeof(BITMAPINFOHEADER));
+		memcpy(pImgData + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), lpbitmap, dwBmpSize);
+		GlobalUnlock(hDIB);
+		GlobalFree(hDIB);
+		
+	done:
+		//DeleteObject(hbmWindow);
+		//DeleteObject(hdcMemDC);
+		//ReleaseDC(hWnd, hdcWindow);
+		CFile file;
+		CFileException fep;
+		if (file.Open("E:\\1.jpg", CFile::modeCreate | CFile::modeWrite, &fep)) {
+			file.Write(pImgData, dwSizeofDIB);
+			file.Close();
+		}
+
+		cv::Mat s22 = cv::imread("E:\\1.jpg");
+		cv::imwrite("E:\\2.jpg",s22);
+
+		//cv::Mat pic;
+		//int nChannels = bmpWindow.bmBitsPixel == 1 ? 1 : bmpWindow.bmBitsPixel / 8;
+		//pic.create(cv::Size(width, height), CV_8UC4);
+		//memcpy(pic.data, lpbitmap, dwBmpSize);
+		cv::_InputArray pirArrary(pImgData, dwSizeofDIB);
+		cv::Mat src = cv::imdecode(pirArrary, cv::IMREAD_COLOR);
+		cv::imwrite("E:\\3.bmp", src);
+		cv::imwrite("E:\\3.jpg", src);
+
+		cv::Mat matPic(height, width, CV_8UC4, pImgData + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
+		cv::imwrite("E:\\4.jpg", matPic);
+		return cv::Mat();
+	}
+
+	BOOL OpenImage(std::string strImag, cv::Mat& img)
+	{
+		if (!PathFileExists(strImag.c_str()))
+			return FALSE;
+
+		if (img.data != NULL)
+			img.release();
+
+		img = cv::imread(strImag.c_str(), cv::IMREAD_COLOR);
+		if (img.data == NULL)
+			return FALSE;
+
+		return TRUE;
+	}
+
+	BOOL SetImgThreshold(cv::Mat& srcImg, cv::Mat& thresholdImg, long nThresholdVal, long nMaxThresholdVal, int type)
+	{
+		if (srcImg.data == NULL)
+			return FALSE;
+
+		if (thresholdImg.data && srcImg.data != thresholdImg.data)
+			thresholdImg.release();
+
+		switch (type)
+		{
+		case 0://全局阀值;
+		{
+			// 转成灰阶图;
+			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
+			// 再高斯模糊处理(滤波);
+			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(5, 5), 0, 0);
+			// 二值化;//全局化指定的阀值与返回值相等;
+			double dRetVal = cv::threshold(thresholdImg, thresholdImg, nThresholdVal, nMaxThresholdVal, cv::THRESH_BINARY);
+		}
+		break;
+		case 1://自适应阀值;
+		{
+			// 转成灰阶图;
+			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
+			// 再高斯模糊处理(滤波);
+			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(3, 3), 0, 0);
+			// 自适应阀值;
+			cv::medianBlur(thresholdImg, thresholdImg, 3);
+			// 局部二值化;//blocksize一般取3、5、7
+			cv::adaptiveThreshold(thresholdImg, thresholdImg, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 3, 4.5);
+		}
+		break;
+		case 2:// otsu阀值;
+		{
+			cv::cvtColor(srcImg, thresholdImg, cv::COLOR_BGR2GRAY);
+			// 高斯模糊;
+			cv::GaussianBlur(thresholdImg, thresholdImg, cv::Size(3, 3), 0, 0);
+			cv::threshold(thresholdImg, thresholdImg, nThresholdVal, nMaxThresholdVal, cv::THRESH_BINARY | cv::THRESH_OTSU);
+		}
+		break;
+		default:
+			break;
+		}
+
+		return TRUE;
+	}
+
+	BOOL GetImgMatchtemplate(HWND hWnd, std::string strTempImg, RECT& rc, double lowestMatchValue)
+	{
+		std::string strImage = CaptureGameWnd(hWnd);
+		cv::Mat srcImg, tempImg, matchImg;
+		if (!OpenImage(strImage, srcImg) || !OpenImage(strTempImg, tempImg))
+		{
+			if (srcImg.data) srcImg.release();
+			if (tempImg.data) tempImg.release();
+			return FALSE;
+		}
+
+		cv::matchTemplate(srcImg, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
+		// 归一化到0~1
+		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
+
+		double lv_nMinVal = 0.0;
+		double lv_nMaxVal = 0.0;
+		cv::Point lv_nMinLoc = cv::Point(0, 0);
+		cv::Point lv_nMaxLoc = cv::Point(0, 0);
+		cv::Point lv_MatchLoc = cv::Point(0, 0);
+		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
+
+		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
+		cv::Mat roiImg = srcImg(roi);
+		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
+
+		rc.left = lv_nMaxLoc.x - GameGlobal::frameWidth;
+		rc.top = lv_nMaxLoc.y - GameGlobal::titleBarHeight;
+		rc.right = rc.left + tempImg.cols;
+		rc.bottom = rc.top + tempImg.rows;
+
+		srcImg.release();
+		tempImg.release();
+		matchImg.release();
+		roiImg.release();
+
+		// 是否大于最低匹配度;
+		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
+	}
+
+	BOOL GetImgMatchtemplate(std::string strSrcImg, std::string strTempImg, RECT& rc, double lowestMatchValue)
+	{
+		cv::Mat srcImg, tempImg, matchImg;
+		if (!OpenImage(strSrcImg, srcImg) || !OpenImage(strTempImg, tempImg))
+		{
+			if (srcImg.data) srcImg.release();
+			if (tempImg.data) tempImg.release();
+			return FALSE;
+		}
+
+		cv::matchTemplate(srcImg, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
+		// 归一化到0~1
+		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
+
+		double lv_nMinVal = 0.0;
+		double lv_nMaxVal = 0.0;
+		cv::Point lv_nMinLoc = cv::Point(0, 0);
+		cv::Point lv_nMaxLoc = cv::Point(0, 0);
+		cv::Point lv_MatchLoc = cv::Point(0, 0);
+		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
+
+		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
+		cv::Mat roiImg = srcImg(roi);
+		//cv::imwrite("G:\\bin\\GameAssist\\match.bmp", roiImg);
+
+		rc.left = lv_nMaxLoc.x - GameGlobal::frameWidth;
+		rc.top = lv_nMaxLoc.y - GameGlobal::titleBarHeight;
+		rc.right = rc.left + tempImg.cols;
+		rc.bottom = rc.top + tempImg.rows;
+
+		srcImg.release();
+		tempImg.release();
+		matchImg.release();
+		roiImg.release();
+
+		// 是否大于最低匹配度;
+		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
+	}
+
+	BOOL IsMatchIcon(HWND hWnd, std::string strTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue)
+	{
+		std::string strImg = CaptureGameWnd(hWnd);
+		cv::Mat srcImg, tempImg, matchImg;
+		if (!OpenImage(strImg, srcImg) || !OpenImage(strTempImg, tempImg))
+		{
+			if (srcImg.data) srcImg.release();
+			if (tempImg.data) tempImg.release();
+			return FALSE;
+		}
+
+		// 指定源图片区域来做模块比较,提高效率;
+		cv::Mat imgROI;
+		imgROI = srcImg(cv::Rect(srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top));
+		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("roi")), imgROI);
+		/*
+		m_ImgROI = srcImg([&]()-> cv::Rect {
+			// 注意是x,y,w=cols,h=rows
+			return cv::Rect(srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top);
+		}());
+		*/
+
+		cv::matchTemplate(imgROI, tempImg, matchImg, cv::TM_CCOEFF_NORMED);
+		// 归一化到0~1
+		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
+
+		double lv_nMinVal = 0.0;
+		double lv_nMaxVal = 0.0;
+		cv::Point lv_nMinLoc = cv::Point(0, 0);
+		cv::Point lv_nMaxLoc = cv::Point(0, 0);
+		cv::Point lv_MatchLoc = cv::Point(0, 0);
+		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
+
+		cv::Rect roi = cv::Rect(lv_nMaxLoc.x, lv_nMaxLoc.y, tempImg.cols, tempImg.rows);
+		cv::Mat roiImg = imgROI(roi);
+		cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
+
+		matchRect.left = srcRect.left + lv_nMaxLoc.x - GameGlobal::frameWidth;
+		matchRect.top = srcRect.top + lv_nMaxLoc.y - GameGlobal::titleBarHeight;
+		matchRect.right = matchRect.left + tempImg.cols;
+		matchRect.bottom = matchRect.top + tempImg.rows;
+
+		imgROI.release();
+		srcImg.release();
+		tempImg.release();
+		matchImg.release();
+		roiImg.release();
+
+		// 是否大于最低匹配度;
+		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
+	}
+
+	BOOL CropPicture(HWND hWnd, CRect rc, const char* szSaveName)
+	{
+		std::string strImg = CaptureGameWnd(hWnd);
+		cv::Mat srcImg, tempImg, matchImg;
+		if (!OpenImage(strImg, srcImg))
+		{
+			if (srcImg.data) srcImg.release();
+			return FALSE;
+		}
+
+		// 指定源图片区域来做模块比较,提高效率;
+		cv::Mat imgROI;
+		imgROI = srcImg(cv::Rect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
+		return cv::imwrite(szSaveName, imgROI);
+	}
+
+	BOOL IsSimilarPicture(const char* szp1, const char* szp2, double lowestMatchValue)
+	{
+		cv::Mat src, dest, matchImg;
+		src = cv::imread(szp1);
+		dest = cv::imread(szp2);
+
+		cv::matchTemplate(src, dest, matchImg, cv::TM_CCOEFF_NORMED);
+		// 归一化到0~1
+		//cv::normalize(matchImg, matchImg, 0, 1, cv::NORM_MINMAX, -1);
+
+		double lv_nMinVal = 0.0;
+		double lv_nMaxVal = 0.0;
+		cv::Point lv_nMinLoc = cv::Point(0, 0);
+		cv::Point lv_nMaxLoc = cv::Point(0, 0);
+		cv::Point lv_MatchLoc = cv::Point(0, 0);
+		cv::minMaxLoc(matchImg, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
+
+		src.release();
+		matchImg.release();
+		dest.release();
+
+		// 是否大于最低匹配度;
+		return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
+	}
+
+	int GetColorOccupiedLength(std::string strImg, int r, int g, int b)
+	{
+		cv::Mat src = cv::imread(strImg.c_str());
+		// 获取图片的矩形大小;
+		int width = src.cols;
+		int height = src.rows;
+
+		int i = 0;
+		for (; i < width; ++i)
+		{
+			cv::Vec3b pixel = src.at<cv::Vec3b>(height / 2, i);	// 读取第 height / 2行 第 i 列像素值;
+			if (abs(pixel[0] - b) <= 3 && abs(pixel[1] - g) <= 3 && abs(pixel[2] - r) <= 3)
+			{
+				continue;
+			}
+
+			break;
+		}
+		src.release();
+
+		GameGlobal::DebugLog(_T("[GameAssist] 颜色占比=%d,%d,%d"), i, width, i * 100 / width);
+
+		return i * 100 / width;
+	}
+
+};

+ 17 - 0
GameAssist/GameAssist/ImgAssist.h

@@ -0,0 +1,17 @@
+#pragma once
+
+namespace ImgAssist 
+{
+	std::string CaptureGameWnd(HWND hWnd);
+	void CaptureGameWnd(HWND hWnd, std::string strSavePath);
+	cv::Mat CaptureWnd(HWND hWnd);
+	BOOL OpenImage(std::string strImag, cv::Mat& img);
+	BOOL SetImgThreshold(cv::Mat& srcImg, cv::Mat& thresholdImg, long nThresholdVal, long nMaxThresholdVal, int type = 0);
+	BOOL GetImgMatchtemplate(HWND hWnd, std::string strTempImg, RECT& rc, double lowestMatchValue = 0.900);
+	BOOL GetImgMatchtemplate(std::string strSrcImg, std::string strTempImg, RECT& rc, double lowestMatchValue = 0.900);
+	BOOL IsMatchIcon(HWND hWnd, std::string strTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue = 0.900);
+	BOOL CropPicture(HWND hWnd, CRect rc, const char* szSaveName); // 剪裁图片;
+	BOOL IsSimilarPicture(const char* szp1, const char* szp2, double lowestMatchValue = 0.99);
+	// 获取指定颜色占用矩形长度比例;
+	int GetColorOccupiedLength(std::string strImg, int r, int g, int b);
+};

+ 84 - 0
GameAssist/GameAssist/KMAssist.cpp

@@ -0,0 +1,84 @@
+#include "stdafx.h"
+#include "KMAssist.h"
+
+// 定义鼠标移动的时间间隔和距离系数
+const int MouseMoveInterval = 10;
+const double MouseMoveDistanceFactor = 1.5;
+
+// 定义辅助函数,计算两点之间的距离
+double Distance(POINT startPt, POINT endPt)
+{
+	return sqrt(pow(startPt.x - endPt.x, 2) + pow(startPt.y - endPt.y, 2));
+}
+
+double Distance(double x1, double y1, double x2, double y2)
+{
+	return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
+}
+
+void KMAssist::MouseMove(POINT endPt, bool bSetCurPos)
+{
+	// 当前坐标;
+	POINT startPt;
+	::GetCursorPos(&startPt);
+
+	// 计算两点距离;
+	double distance = Distance(startPt.x, startPt.y, endPt.x, endPt.y);
+
+	// 计算鼠标移动的偏移量
+	int dx = (int)((endPt.x - startPt.x) * MouseMoveDistanceFactor / distance);
+	int dy = (int)((endPt.y - startPt.y) * MouseMoveDistanceFactor / distance);
+
+	// 计算鼠标相对屏幕坐标的绝对坐标值;
+	static long fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN) - 1;
+	static long fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN) - 1;
+	// 使用浮点数,计算出来的值转Long会更精确;
+	double fx = (double)endPt.x * (65535.0f / fScreenWidth);
+	double fy = (double)endPt.y * (65535.0f / fScreenHeight);
+
+	INPUT Input = { 0 };
+	Input.type = INPUT_MOUSE;
+	Input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+	Input.mi.dx = static_cast<LONG>(fx);
+	Input.mi.dy = static_cast<LONG>(fy);
+	::SendInput(1, &Input, sizeof(INPUT));
+
+	// Move之后设置当前鼠标位置;
+	if (bSetCurPos)::SetCursorPos(endPt.x, endPt.y);
+}
+
+void KMAssist::MouseMove(int x, int y, bool bSetCurPos)
+{
+}
+
+void KMAssist::MouseClick()
+{
+}
+
+void KMAssist::MouseClick(POINT pt)
+{
+}
+
+void KMAssist::MouseDbClick()
+{
+}
+
+void KMAssist::MouseDbClick(POINT pt)
+{
+}
+
+void KMAssist::MouseRClick()
+{
+}
+
+void KMAssist::MouseRClick(POINT pt)
+{
+}
+
+void KMAssist::MouseDrag(POINT pt)
+{
+}
+
+void KMAssist::SendKey(DWORD key, BOOL bCtrl, BOOL bAtl, BOOL bShift)
+{
+}

+ 22 - 0
GameAssist/GameAssist/KMAssist.h

@@ -0,0 +1,22 @@
+#pragma once
+namespace KMAssist
+{
+	// 報炎卞強;
+	void MouseMove(POINT pt, bool bSetCurPos = true);
+	void MouseMove(int x, int y, bool bSetCurPos = true);
+	// 報炎汽似;
+	void MouseClick();
+	void MouseClick(POINT pt);
+	// 報炎褒似;
+	void MouseDbClick();
+	void MouseDbClick(POINT pt);
+	// 報炎嘔似;
+	void MouseRClick();
+	void MouseRClick(POINT pt);
+	// 報炎溶強;
+	void MouseDrag(POINT pt);
+
+	// 窟僕梓囚;
+	void SendKey(DWORD key, BOOL bCtrl = FALSE, BOOL bAtl = FALSE, BOOL bShift = FALSE);
+};
+