123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- #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 = rcc.right - rcc.left;
- int height = rcc.bottom - rcc.top;
- int dx = rc.right - rc.left - width;
- int dy = rc.bottom - rc.top - height;
- // 创建兼容位图;
- hbmpWindow = ::CreateCompatibleBitmap(hdcWindow, width, height);
- // 将位图选入兼容DC;
- SelectObject(hdcMemDC, hbmpWindow);
- #if 1
- // 将窗口复制到兼容DC中(当窗口被遮挡时,这个函数效果好)
- if(!::PrintWindow(hWnd, hdcMemDC, PW_CLIENTONLY))
- {
- 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(hbmpWindow);
- DeleteObject(hdcMemDC);
- ReleaseDC(hWnd, hdcWindow);
- #if 0 // 原始的保留图片做法;
- 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);
- #endif
- //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);
- if (pImgData)
- {
- cv::_InputArray pirArrary(pImgData, dwSizeofDIB);
- cv::Mat src = cv::imdecode(pirArrary, cv::IMREAD_COLOR);
- delete[]pImgData;
- pImgData = NULL;
- #ifdef DEBUG
- cv::imwrite("E:\\3.bmp", src); // 后缀不一样,得到的大小也不一样;
- cv::imwrite("E:\\3.jpg", src);
- #endif
- return src;
- }
- #if 0 // 能保存截图,但是被270度镜像;
- cv::Mat matPic(height, width, CV_8UC4, pImgData + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
- cv::imwrite("E:\\4.jpg", matPic);
- #endif
- 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;
- }
- cv::Mat OpenImage(std::string strImage)
- {
- if (!PathFileExists(strImage.c_str()))
- return cv::Mat();
- cv::Mat img = cv::imread(strImage.c_str(), cv::IMREAD_COLOR);
- if (img.data == NULL)
- return cv::Mat();
- return cv::Mat();
- }
- 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, cv::Mat cvTempImg, RECT& rc, double lowestMatchValue)
- {
- cv::Mat srcImg = CaptureWnd(hWnd);
- return GetImgMatchtemplate(srcImg, cvTempImg, rc, lowestMatchValue);
- }
- BOOL GetImgMatchtemplate(cv::Mat cvSrcImg, cv::Mat cvTempImg, RECT& rc, double lowestMatchValue)
- {
- if (cvSrcImg.empty() || cvTempImg.empty())
- {
- if (cvSrcImg.data) cvSrcImg.release();
- if (cvTempImg.data) cvTempImg.release();
- return FALSE;
- }
- cv::Mat matchImg;
- cv::matchTemplate(cvSrcImg, cvTempImg, 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, cvTempImg.cols, cvTempImg.rows);
- cv::Mat roiImg = cvSrcImg(roi);
- #ifdef DEBUG
- cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
- #endif
- rc.left = lv_nMaxLoc.x - GameGlobal::frameWidth;
- rc.top = lv_nMaxLoc.y - GameGlobal::titleBarHeight;
- rc.right = rc.left + cvTempImg.cols;
- rc.bottom = rc.top + cvTempImg.rows;
- cvSrcImg.release();
- cvTempImg.release();
- matchImg.release();
- roiImg.release();
- // 是否大于最低匹配度;
- return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
- }
- BOOL GetImgMatchtemplate(HWND hWnd, std::string strTempImg, RECT& rc, double lowestMatchValue)
- {
- cv::Mat tempImg = OpenImage(strTempImg);
- return GetImgMatchtemplate(hWnd, tempImg, rc, lowestMatchValue);
- }
- BOOL GetImgMatchtemplate(std::string strSrcImg, std::string strTempImg, RECT& rc, double lowestMatchValue)
- {
- cv::Mat srcImg = OpenImage(strSrcImg), tempImg = OpenImage(strTempImg);
- return GetImgMatchtemplate(srcImg, tempImg, rc, lowestMatchValue);
- }
- BOOL IsMatchIcon(cv::Mat cvSrcImg, cv::Mat cvTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue)
- {
- if (cvSrcImg.empty() || cvTempImg.empty())
- {
- if (cvSrcImg.data) cvSrcImg.release();
- if (cvTempImg.data) cvTempImg.release();
- return FALSE;
- }
- // 指定源图片区域来做模块比较,提高效率;
- cv::Mat imgROI = cvSrcImg(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::Mat matchImg;
- cv::matchTemplate(imgROI, cvTempImg, 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, cvTempImg.cols, cvTempImg.rows);
- cv::Mat roiImg = imgROI(roi);
- #ifdef DEBUG
- cv::imwrite(GameGlobal::BuildImgPath(hWnd, _T("match")), roiImg);
- #endif
- matchRect.left = srcRect.left + lv_nMaxLoc.x - GameGlobal::frameWidth;
- matchRect.top = srcRect.top + lv_nMaxLoc.y - GameGlobal::titleBarHeight;
- matchRect.right = matchRect.left + cvTempImg.cols;
- matchRect.bottom = matchRect.top + cvTempImg.rows;
- imgROI.release();
- cvSrcImg.release();
- cvTempImg.release();
- matchImg.release();
- roiImg.release();
- // 是否大于最低匹配度;
- return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
- }
- BOOL IsMatchIcon(HWND hWnd, std::string strTempImg, RECT srcRect, RECT& matchRect, double lowestMatchValue)
- {
- cv::Mat srcImg = CaptureWnd(hWnd), tempImg = OpenImage(strTempImg);
- return IsMatchIcon(srcImg, tempImg, srcRect, matchRect, lowestMatchValue);
- }
- BOOL CropPicture(HWND hWnd, CRect rc, const char* szSaveName)
- {
- cv::Mat imgROI = CropPicture(hWnd, rc);
- return cv::imwrite(szSaveName, imgROI);
- }
- cv::Mat CropPicture(HWND hWnd, CRect rc)
- {
- cv::Mat srcImg = CaptureWnd(hWnd), tempImg, matchImg;
- if (srcImg.empty())
- {
- if (srcImg.data) srcImg.release();
- return cv::Mat();
- }
- // 指定源图片区域来做模块比较,提高效率;
- cv::Mat imgROI;
- return srcImg(cv::Rect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
- }
- BOOL IsSimilarPicture(const char* szp1, const char* szp2, double lowestMatchValue)
- {
- return IsSimilarPicture(cv::imread(szp1), cv::imread(szp2), lowestMatchValue);
- }
- BOOL IsSimilarPicture(cv::Mat src1, cv::Mat src2, double lowestMatchValue)
- {
- cv::Mat matchImg;
- cv::matchTemplate(src1, src2, 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);
- src1.release();
- matchImg.release();
- src2.release();
- // 是否大于最低匹配度;
- return (lv_nMaxVal >= lowestMatchValue ? TRUE : FALSE);
- }
- int GetColorOccupiedLength(std::string strImg, int r, int g, int b)
- {
- return GetColorOccupiedLength(cv::imread(strImg.c_str()), r, g,b);
- }
- int GetColorOccupiedLength(cv::Mat src, int r, int g, int b)
- {
- // 获取图片的矩形大小;
- 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;
- }
- };
|