QQ游戏找茬终结者

回想起四年前,自己大二刚开始学C#时,发现Bitmap类中有GetPixel方法的时候一阵狂喜。因为那时我玩过一款QQ游戏——大家来找茬,这个游戏是从画幅图中找出不一样的地方。如果可以获取到图片的每个像素值,只要发现其像素值不一样,即可判断图的这个地方不一样了(当然,这得假设腾讯没有对图片进行一些小的处理,比如,一个图的像素值RGB都加1,这时在肉眼是看不出区别的,但可以防止我用这样的方法做出外挂。而实际上,腾讯没有做这样的处理,所以~~~)。再用其它的一些办法(我的方法是自己再创建一个透明窗体,覆盖在一个图片上,不同的像素点用红色标记出来),将这些不同的像素点,显示给我们看,在玩游戏时就可以一下子找到所有的不同。(注意,这里是是标出所有的不同像素点,而还是得我们自己手动去点击

如下所示,将一幅图中所有不同的地方都用红色标记出来,然后我们只需要点击。

QQ游戏找茬终结者

然后,因为要实现上面我所说的这些功能,自己学会了用C#调用win32API截屏,并且也发现可以用win32API获取其它窗体的位置、区域之类的信息,可以说这个QQ找茬的外挂开启了自己学习win32API之路。

这个C#版的程序没有多大的难度。

今年上半年时,自己用c++也实现了同样的功能,不过为了和四年前有所不一样,准备完善聚类分析。找茬游戏中只有5处不一样的地方,而用像素找出来的不一样点将非常多,如果程序可以自动将所有这些点正确地聚类成5类,那么程序就可以自动点击了。其实这个功能自己当初就想过,可当时自己能力、视野都有限,没能完成。不过,现在自己在图像处理上小有所获后,再来看这个问题,觉得可以实现了。

首先,自己尝试用了openCV中的cvKMeans2方法,其使用K均值聚类。但实现效果不好,错误率很高。

现在本人想到的方法是,在那些有差别的像素点上找连通区域,最后只取5个最大的连通区域。如果图片中的5个不同区域不彼此靠近,那么就可以完美地解决问题,但实际情况有些是有几个块会连在一起,这样就得用另外的方法重新考虑了。不过,先将简单的情况实现了再说。而找区域连通性的方法自己以前就有实现过,那么剩下的工作就非常少了。于是就有了下面的效果(非常惊艳)——

QQ游戏找茬终结者

(我将分成的5个分别用不同的颜色标识出来了) 这时就可以操作鼠标去自动点击了,5个不同的点可以瞬间找出来。以至于在游戏中测试这个程序时,其他的玩家一盘下来就都跑了~~

上面用的区域检测算法有参照《图像编程精髓:从开发自己的Photoshop开始》,实现的思路不是很复杂,在这就直接贴出代码,就不去仔细说明了。

View Code
  1     namespace image

  2     {

  3         using namespace std;

  4         namespace  //名字空间内的私有函数

  5         {

  6             typedef struct 

  7             {

  8                 int Sign;   //标志

  9                 int Area;   //面积

 10             }AreaInfo; //用于统计面积的大小与标记的关系

 11 

 12             inline bool AreaSortFun(const AreaInfo &a1,const AreaInfo &a2)

 13             {

 14                 return a1.Area>a2.Area;

 15             }

 16             inline  void ReplaceSign(TwoDimesionArray<int> &signs,int bottom,int srcSign,int dstSign)

 17             {

 18                 for (int i=0;i<signs.GetWidth();++i)

 19                 {

 20                     for (int j=0;j<=bottom;++j)

 21                     {

 22                         if(signs.GetValue(i,j)==srcSign)

 23                             signs.SetValue(i,j,dstSign);

 24                     }

 25                 }

 26             }

 27  

 28 

 29         }//end namespace

 30 

 31         inline int IsHaveAreaTag(vector<AreaInfo> &areas,int tag) 

 32         {

 33             for (int i=0;i<areas.size();++i)

 34             {

 35                 if(areas[i].Sign ==tag)

 36                     return i;

 37             }

 38             return -1;

 39         }

 40 

 41         inline TwoDimesionArray<int> GetAreaInfo(TwoDimesionArray<bool> bs,  vector<AreaInfo> &areaInfos)

 42         {

 43             //vector<vector<int>> sameTag;

 44             TwoDimesionArray<int> signs(bs.GetWidth(),bs.GetHeight());

 45             signs.SetAllValue(0);

 46             int signNo=1;

 47             for (int x=0;x<bs.GetWidth();++x) //先处理顶行

 48             {

 49                 if(!bs.GetValue(x,0))

 50                 {

 51                     continue;

 52                 }

 53                 while(x<bs.GetWidth() && bs.GetValue(x,0))

 54                 {

 55                     signs.SetValue(x,0,signNo);

 56                     ++x;

 57                 }

 58                 ++signNo;

 59             }

 60             for (int j=1;j<bs.GetHeight();++j)  //处理最左和最右列

 61             {

 62                 if(bs.GetValue(0,j))  //最左列

 63                 {

 64                     if(bs.GetValue(0,j-1))

 65                     {

 66                         signs.SetValue(0,j,signs.GetValue(0,j-1));

 67                     }

 68                     else

 69                     {

 70                         signs.SetValue(0,j,signNo++);

 71                     }

 72                 }

 73                 if(bs.GetValue(bs.GetWidth()-1,j)) //最右列

 74                 {

 75                     if(bs.GetValue(bs.GetWidth()-1,j-1))

 76                     {

 77                         signs.SetValue(bs.GetWidth()-1,j,signs.GetValue(bs.GetWidth()-1,j-1));

 78                     }

 79                     else

 80                     {

 81                         signs.SetValue(bs.GetWidth()-1,j,signNo++);

 82                     }

 83                 }

 84             }

 85             for (int j=1;j<bs.GetHeight();++j)

 86             {

 87                 for (int i=1;i<bs.GetWidth()-1;++i)

 88                 {

 89                     if(!bs.GetValue(i,j))

 90                         continue;

 91                     if(bs.GetValue(i+1,j-1)) //右上

 92                     {

 93                         int sign=signs.GetValue(i+1,j-1);

 94                         signs.SetValue(i,j,sign);

 95                         if(bs.GetValue(i-1,j) && signs.GetValue(i-1,j) != sign)  //右上与左前不同标记

 96                         {

 97                             //AddTag(sameTag,signs.GetValue(i-1,j),tag);

 98                             ReplaceSign(signs,j,signs.GetValue(i-1,j),sign);

 99                         }

100                         else if(bs.GetValue(i-1,j-1) && signs.GetValue(i-1,j-1) != sign) //右上与左上不同标记

101                         {

102                             //AddTag(sameTag,signs.GetValue(i-1,j-1),tag);

103                             ReplaceSign(signs,j,signs.GetValue(i-1,j-1),sign);

104                         }

105                     }

106                     else if(bs.GetValue(i,j-1))  //正上

107                     {

108                         signs.SetValue(i,j,signs.GetValue(i,j-1));

109                     }

110                     else if(bs.GetValue(i-1,j-1)) //左上

111                     {

112                         signs.SetValue(i,j,signs.GetValue(i-1,j-1));

113                     }

114                     else if(bs.GetValue(i-1,j)) //左前

115                     {

116                         signs.SetValue(i,j,signs.GetValue(i-1,j));

117                     }

118                     else

119                     {

120                         signs.SetValue(i,j,signNo++);

121                     }

122                 }

123             }  //end two for

124 

125             for (int i=0;i<signs.GetWidth();++i)

126             {

127                 for (int j=0;j<signs.GetHeight();++j)

128                 {

129                     //find(areas.begin(),areas.end())

130                     //if()

131                     int t=IsHaveAreaTag(areaInfos,signs.GetValue(i,j));

132                     if (t!=-1)

133                     {

134                         ++areaInfos[t].Area;

135                     }

136                     else

137                     {

138                         AreaInfo info;

139                         info.Sign=signs.GetValue(i,j);

140                         info.Area=1;

141                         areaInfos.push_back(info);

142                     }

143                 }

144             }//end for

145             return signs;

146         }//end function

147 

148 

149     }//end namespace image

可运行的程序在这 FindDifference  

源程序在SVN上 :svn://svn.jundie.net/FindDifference

这个程序中自己用的是CxImage图像库,这个库自己应该快用了一年多的时间了,现在越来越觉得这个库太不灵活了,与MFC的结合也不是很好。准备以后彻底转向openCV的学习。

这里总结出一个经验:掌握知识最好的文法就是尝试着用它,改进它,并且创新~~

你可能感兴趣的:(游戏)