续上文:
QQ美女找茬(外挂)学习笔记(一)截图的实现与保存
http://www.cppblog.com/ArthasLee/archive/2010/11/18/134022.html比较两幅图片的不同过程中,笔者直接用了 == 来比较,尽管XOR会效率高点。
以下是笔者的代码,非完全原创,有参考,至于具体URL,在上一篇已经跟大家公布过:
1void CZhaoChaV30Dlg::CompareBMP( DWORD*& pBuffer, DWORD* pLeft, DWORD* pRight )
2{
3 if( !pBuffer )
4 {
5 delete []pBuffer;
6 pBuffer = NULL;
7 }
8
9 pBuffer = new DWORD[ nWidth * nHeight ];
10 //比较两幅图,数据相同的设置为白色,不同的为红色。
11 for (DWORD i = 0; i < (DWORD)nWidth * nHeight; i++ )
12 {
13 if( pLeft[ i ] != pRight[ i ] )
14 pBuffer[ i ] = RGB( 0,0,255 );
15 else
16 pBuffer[ i ] = pLeftBuffer[ i ] ;
17 }
18
19 //转换图片数据,使图片按正常顺序显示。(BMP格式与窗口图像存放竖坐标相反)
20 //笔者开始一直不是很明白该位blog主的意思,为什么要倒转y坐标;
21 //因此就把下面的注释掉,从windows图片浏览器观察位图,发现位图显示出来的时候并没有倒转;
22 //直至在后来要把位图显示到窗口上才真切理解“BMP格式与窗口图像存放竖坐标相反”这个事实;
23 //要注意,不然日后要写全自动WG,直接由机器发送鼠标消息模拟点击的时候就杯具了。
24 int width = nWidth;
25 for ( DWORD i = 0; i < (DWORD)(nHeight / 2); i++ )
26 {
27 for ( DWORD j = 0; j < (DWORD)width; j++ )
28 {
29 DWORD temp;
30 temp = *( pBuffer + i * width + j );
31 *( pBuffer + i * width + j ) = *( pBuffer + width * ( nHeight - 1 - i ) + j );
32 *( pBuffer + width * ( nHeight - 1 - i ) + j ) = temp;
33 }
34 }
35
36}
37
传入三个pBuffer,然后对后面两个参数的内容进行比较,然后把比较结果写入第一个pBuffer指向的内存空间中。这段代码笔者还是好好学习了下,大家留意注释。
比较完成以后,当然是要把比较的成果显示到程序主窗口的客户区中。不然之前一切的努力也就白费了。
1void CZhaoChaV30Dlg::BMPToWnd( void )
2{
3 CBitmap bm;
4 CDC* pDC;
5
6 bm.CreateBitmap( nWidth, nHeight, 1, 32, pBuffer );
7 CBrush brush;
8 brush.CreatePatternBrush( &bm );
9
10 pDC = GetDC();
11 CBrush* pOldBrush = (CBrush*)pDC -> SelectObject( &brush );
12
13 pDC->FillRect( &CRect( 0, 0, nWidth, nHeight ), &brush );
14
15 pDC->SelectObject( pOldBrush );
16
17 brush.DeleteObject();
18 bm.DeleteObject();
19 ReleaseDC(pDC);
20}
在上面的代码中,有个函数是CreateBitmap,与之前截图用到的CreateCompatableBitmap有点相似,笔者有点好奇,拜了google大神后,找到了以下的文章:
http://hi.baidu.com/550189285/blog/item/3742cfd4f8c9f30ba08bb775.htmlPS:尽管随便贴URL是不道德滴,但是学习资料不保留下来更加不道德~
一般来说,WG来到这里,就差不多了。因为我们的基本目标已经达到。
but。。。
其余的细节呢?
要不要令这个WG更自动化,让“它”自己“玩”游戏呢?
又该如何实现呢???
以下是笔者在编码过程中遇到的问题和解决心得:
再次声明,此乃笔记,不具有普适性,有错误和改进,欢迎指出~
问题3:比较图片和一个奇怪的现象?
背景:
捕获了图片之后开始对两幅相同的图像进行比较,可以选取每个像素点进行比较,方法有二:直接用 == 比较,或者将两个点进行Xor运算。但是由此比较出来的图片,却出现了“重影现象”;
如下图所示:
子问题:什么原因导致此现象?
解决方案:
分析:笔者对比了几个失败样本之后,发现重影多数是出现在X方向上,Y方向上则没有明显现象。如果这种现象是由色差这样微小的非肉眼能识别的区别而造成的,那么应该整张图也出现重影,而不应该在某一个方向上出现特别显著的重影。
结论:
两幅图在X坐标上有1个像素的偏移,笔者没有自己通过任何技术手段去获取两幅图片左上角的确切坐标,只是google了一下,就找到了相关的文章:
http://student.csdn.net/space.php?uid=110891&do=blog&id=38571
这个链接在笔者的上一篇文章已经提到过。
关键的数字们~
x1 = 8;
y1 = 193;
x2 = 516 + 1; //左右两副图本身有偏移个像素,去掉偏移的,只比较共有的部分
y2 = 193;
nWidth = 498 - 1;//左右两副图本身有偏移个像素,去掉偏移的,只比较共有的部分
nHeight = 448;
感想:
遇到问题的时候,google很重要。
问题4:将比较结果显示到更新了的窗口上:
背景:
位图信息被保存在pBuffer上,为了整个程序可以仅仅透过pBuffer来沟通,放弃了之前的hdcWindow和hBitMap等变量的使用(让它们在截图函数返回前就被销毁)。因此,MSDN上的那段关于截图的代码的后半部分就不能再用。
子问题:
在位图内容已经存在的情况下,通过pBuffer,如何把位图显示到窗口上?
解决方案:
创建一个滑刷,CBrush brush;然后把pBuffer里面的像素填充进去。但是注意填充之前要保证pBuffer里面的纵坐标被倒转一下再显示到窗口中,不然会出现倒转,详见笔者在上面的代码,有中文注释。
问题5:隐藏窗口时的延迟性造成截图干扰
背景:
按下display按钮进行找茬之后,需要隐藏窗口再进行截图,不知道是机器原因还是别的问题,窗口还没有隐藏好,可能截图操作就已经完成了,这是截下的图就会是包含了“窗口残像”的图,再进行比较当然毫无意义。
例如出现了这样的“灵异事件”:
分析:
显然是窗口还没有完全隐藏,截图就进行了,so……
详情见代码:
1void CZhaoChaV30Dlg::OnBnClickedButtonDisplay()
2{
3 // TODO: 在此添加控件通知处理程序代码
4 ShowWindow( SW_HIDE );
5 Sleep( 500 );// Good code!
6
7 pBuffer = NULL;
8#ifdef DEBUG_CODE
9 CaptureImage( pLeftBuffer, x1, y1, nWidth, nHeight );
10 SaveBMP( pLeftBuffer, _T("Debug_1.bmp") );
11 CaptureImage( pRightBuffer, x2, y2, nWidth, nHeight );
12 SaveBMP( pRightBuffer, _T("Debug_2.bmp") );
13 CompareBMP( pBuffer, pLeftBuffer, pRightBuffer );
14 SaveBMP( pBuffer, _T("Result.bmp") );
15#else
16 CaptureImage( pLeftBuffer, x1, y1, nWidth, nHeight );
17 CaptureImage( pRightBuffer, x2, y2, nWidth, nHeight );
18 CompareBMP( pBuffer, pLeftBuffer, pRightBuffer );
19#endif
20 ShowWindow( SW_SHOW );
21
22 //RetSetWnd();
23 BMPToWnd();
24}
解决方案:
隐藏窗口代码后加一行:Sleep( 500 );
让程序“休息”一下,这样就可以等窗口完全隐藏过后才开始截图。
感想:
Sleep真神奇~
理想状态下一切都很理想,但实际操作的时候,还是会出现某些非理论性延迟。这时需要coder们灵活变通,处理一下这个延迟了的“消息”~
鸣谢:
jingzhongrong——提供了不少测试样例和分析案例,从反面促使笔者尽快完成此文;
vczh——从正面鼓励笔者尽快完成此文;
vczh:
http://www.cppblog.com/vczh/
posted on 2010-11-24 00:02
ArthasLee 阅读(3518)
评论(14) 编辑 收藏 引用 所属分类:
windows应用层编程