找茬游戏
最近在整理硬盘时,看到了几年前写的 美女找茬工具,一时兴起看下现在是否能用,试了下,完全用不了了,界面和以前的界面一样啊,图片的偏移应该没有变,按道理应该能用,猜想可能是图片做了处理。就花了点时间看了下,果然发现了问题,现在和大家分享下。
原理
找茬游戏是给出两种图片,图片中只有几处地方不同,快速找到不同地方的游戏。原理是通过程序拿到两种图片,然后逐像素对比来找到不同地方。
图片获取
- hMainWnd = ::FindWindow(NULL, L”大家来找茬”)); // 拿到找茬的窗口handle,是需要管理员权限
- hDC = GetDC(hMainWnd); // 获取找茬的Device Context
- BitBlt(desDC, desX, desY, width, height, srcDC, srcX, srcY, SRCCOPY); // 该函数是从hDC上从(srcX, srcY)拷贝[width, height]像素到desDC中(desX, desY)指定的位置
一些细节上的东西,可能更需要时间,如找图片的偏移地址,我可以采用的方法是:截图,然后用系统自带的图片编辑器放大来看。
图片对比
此时已经拿到两种图片,就需要对像素进行对比,若相同不处理,若不同则将该像素设置为红色,这样方便我们看到不同的地方。
for (int i = 0; i < mWidth; i++) {
for (int j = 0; j < mHeight; j++) {
COLORREF left = GetPixel(hMemDc, i, j); // 取左边图片像素
COLORREF right = GetPixel(hMemDc, i + delta, j); // 取右边图片像素
bool isEqual = ComparePixel(left, right); // 像素对比
if (!isEqual) {
SetPixel(hMemDc, i, j, 0x00FF); // 设置为红色,当然其他颜色也可以,主要是容易看到差异
}
}
}
/**
*像素对比函数, 早期版本图片相同的地方像素值都是一样的,用left == right来判断就行,
*最新的版本上这种方式已经不可以了,对每个像素都做了处理,处理的原则肯定是保证视觉上没有差异,
*找个几个例子发现,每个字节的高位进行了加一或者减一处理,低位进行了加减4的处理,
*我们处理方式是每个字节不判断低位,只判断高位差异是否为0或者1,若3个字节都满足,则认为像素相同。
*/
bool CZhaochaDlg::ComparePixel(COLORREF left, COLORREF right) {
long value = ((left & 0xFF) >> 4) - ((right & 0xFF) >> 4);
bool low = abs(value) <= 1;
value = ((left & 0xFF00) >> 12) - ((right & 0xFF00) >> 12);
bool middle = abs(value) <= 1;
value = ((left & 0xFF0000) >> 20) - ((right & 0xFF0000) >> 20);
bool high = abs(value) <= 1;
return low && middle && high;
}
注意地方,可以先将两种图片输出看下是否位置找对了,然后分别输出left和right像素来看,是否偏移delta找对了,只有确保这两个找对的前提下,在逐像素来分析规律。
工具
界面主要三部分:
1. 图片展示,不同地方用红色来标识;
2. 配置信息,是为了适应以后图片位置的调整,这样就不需要修改程序;
3. 开始和获取图片,在新开一个找茬窗口或者修改配置信息时,是需要点击”开始”,然后之后每次只需要点击获取图片。
优化空间
可以看到,除了几处大的红色部分外,还有小的密密麻麻的红色区域,是个就是应该上述判断方法不能涵盖所有情况引起的,所以还有不少的优化空间,一种方案是将颜色分成用(R,G,B)表示,类似于三位空间(X,Y,Z)一样,求出两点之间的距离,小于某个阈值表示颜色相同。