續上文:
QQ美女找茬(外掛)學習筆記(一)截圖的實現與保存
http://www.shnenglu.com/ArthasLee/archive/2010/11/18/134022.html比較兩幅圖片的不同過程中,筆者直接用了 == 來比較,盡管XOR會效率高點。
以下是筆者的代碼,非完全原創,有參考,至于具體URL,在上一篇已經跟大家公布過:
1
void 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指向的內存空間中。這段代碼筆者還是好好學習了下,大家留意注釋。
比較完成以后,當然是要把比較的成果顯示到程序主窗口的客戶區中。不然之前一切的努力也就白費了。
1
void 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……
詳情見代碼:
1
void 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.shnenglu.com/vczh/
posted on 2010-11-24 00:02
ArthasLee 閱讀(3559)
評論(14) 編輯 收藏 引用 所屬分類:
windows應用層編程