效果演示:
1.功能介绍:
1.1实现了游戏窗口的检测
1.2实现了检测两张不一样图的位置确定
1.3实现了对两张图不同地方的"特殊"显示:以下就是生成图
以下就是生成图中"特殊部分"的显示
1.4综上,根据图片,选出游戏中不同的地方
2.代码讲解:
2.1监控桌面内容
首先我是利用截图,实现监控桌面的内容,因为是找不同,并不是动态图,我就利用系统截图完成了对桌面的监控。下面就是截图桌面功能的实现
//获取桌面窗口的CDC 相当于画布,你可以使用笔、刷、位图、字体等在画笔上画图CDC *pdeskdc = GetDesktopWindow()->GetDC();CRect re;//获取窗口的大小GetDesktopWindow()->GetClientRect(&re);CBitmap bmp;bmp.CreateCompatibleBitmap(pdeskdc, re.Width(), re.Height());//创建一个兼容的内存画板CDC memorydc;memorydc.CreateCompatibleDC(pdeskdc);//选中画笔CBitmap *pold = memorydc.SelectObject(&bmp);//绘制图像 //x:目标矩形区域的左上角x轴坐标点。//y:目标矩形区域的左上角y轴坐标点。//nWidth:在目标设备中绘制位图的宽度。//nHight:在目标设备中绘制位图的高度。//pdeskdc:源设备上下文对象指针。//xSrc:源设备上下文的起点x轴坐标,函数从该起点复制位图到目标设备。//ySrc:源设备上下文的起点y轴坐标,函数从该起点复制位图到目标设备。//SRCCOPY:光栅操作代码memorydc.BitBlt(0, 0, re.Width(), re.Height(), pdeskdc, 0, 0, SRCCOPY);//获取鼠标位置,然后添加鼠标图像CPoint po;GetCursorPos(&po);HICON hinco = (HICON)GetCursor();memorydc.DrawIcon(po.x - 10, po.y - 10, hinco);//选中原来的画笔memorydc.SelectObject(pold);BITMAP bit;bmp.GetBitmap(&bit);//DWORD size = bit.bmWidth * bit.bmHeight ;//定义 图像大小(单位:byte)DWORD size = bit.bmWidthBytes * bit.bmHeight;LPSTR lpdata = (LPSTR)GlobalAlloc(GPTR, size);//后面是创建一个bmp文件的必须文件头,想要了解可以参考msdnBITMAPINFOHEADER pbitinfo;pbitinfo.biBitCount = 24;pbitinfo.biClrImportant = 0;pbitinfo.biCompression = BI_RGB;pbitinfo.biHeight = bit.bmHeight;pbitinfo.biPlanes = 1;pbitinfo.biSize = sizeof(BITMAPINFOHEADER);pbitinfo.biSizeImage = size;pbitinfo.biWidth = bit.bmWidth;pbitinfo.biXPelsPerMeter = 0;pbitinfo.biYPelsPerMeter = 0;GetDIBits(pdeskdc->m_hDC, bmp, 0, pbitinfo.biHeight, lpdata,(BITMAPINFO*)&pbitinfo, DIB_RGB_COLORS);BITMAPFILEHEADER bfh;bfh.bfReserved1 = bfh.bfReserved2 = 0;bfh.bfType = ((WORD)('M' << 8) | 'B');bfh.bfSize = 54 + size;bfh.bfOffBits = 54;
然后写入base6.jpg 文件中去
//写入文件CFile file;if (file.Open((LPCTSTR)L"base6.jpg", CFile::modeCreate | CFile::modeWrite))//if (file.Open("1.bmp", CFile::modeCreate | CFile::modeWrite)){file.Write(&bfh, sizeof(BITMAPFILEHEADER));file.Write(&pbitinfo, sizeof(BITMAPINFOHEADER));file.Write(lpdata, size);file.Close();}
我这边展示一下上面动图中截图的内容是什么(正常来说不会出现我这个录屏软件,所以大家不用管):
2.2对上面图片base6.jpg的内容进行处理:窗口检测位置
由于前期做了很多无用功,所以这个软件整个完成时间也就几天时间
下面的代码就是检测游戏窗口的位置,实现思路就是二值化后,找到窗口第一根白色水平线(我设置大于100个像素就算我们窗体位置)最左边的位置位置,记录坐标,用这个坐标来确定整个窗体位置。
Mat image = imread("base6.jpg");//转化成二值图Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);cv::Mat contours;cv::Canny(gray,contours,250, //调了了很长时间,还是感觉大于875为边缘,小于250不是边缘效果最好。875);//imshow("Canny", contours);int hight, width;hight = image.rows;width = image.cols;//用于记录连续像素点存在的次数int number = 0;bool istrue = false;//截图窗口的高和宽int imageheight, imagewidth;//int widthget;for (int i = 0; i < hight; i++){uchar* data = contours.ptr<uchar>(i);//wfor (int j = 0; j < width; j++){if (istrue){break;}//white = 255;if ((int)data[j] != 0){//widthget = j;number++;if (number>100){cout << "number:" << number;number = 0;cout << "高:" << i << "宽:" << j - 101 << endl;imageheight = i;imagewidth = j - 101;istrue = true;break;}}else{//如果断一次,都要初始化值,防止当前行存在其他像素的干扰number = 0;}}//每行遍历结束,若未发现游戏边框,便要初始化记录值number = 0;}
2.3把两幅图的内容截取出来
由于上一个内容就是找到了窗体位置,那么我们的窗体内的两幅图的位置就很好找了,我这里为了早点能完成作业,就直接设置像素开始切割出来两幅图片了。
Rect mainimage(imagewidth, imageheight, 1282, 959);//imshow("切割图", mainimage);Mat ROImainImage = image(mainimage);//imshow("ROImainImage",ROImainImage);Rect rectLeft(117, 390, 474, 356);Rect rectRight(688, 390, 474, 356);Mat ROILeft = ROImainImage(rectLeft);Mat ROIRight = ROImainImage(rectRight);
2.3根据bitwise_xor(inputImage1,inputImage2,outputImage)函数处理两张图做xor运算
由于上一个内容,把两幅图截取了出来,所以根据两幅图,完成xor运算
Mat outputimage, out, andout;bitwise_xor(ROILeft, ROIRight, outputimage);imshow("xor", outputimage);
综上就完成了大家来找茬辅助外挂
3.尚存bug:
3.1窗口左上角尽量不要碰到其他图标,以免检测不到窗口
3.2推荐使用黑底的壁纸,或者全黑,以免检测不到窗口
3.3不要遮挡游戏窗口内的画面,以免出现错误。
4.github地址:/index9-44/opencv.git
5.如果出现无法编译或者找不到opencv_world342d.lib错误,请依次检查我项目的opencv位置(我的opencv文件位置在D盘:D:\OpenCV)与您的位置是否一致,或者修改我项目opencv的位置。
如果觉得《opencv实训记录(大家来找茬辅助外挂)》对你有帮助,请点赞、收藏,并留下你的观点哦!