zoukankan      html  css  js  c++  java
  • QQ游戏找茬终结者

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

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

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

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

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

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

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

    (我将分成的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的学习。

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

  • 相关阅读:
    深度学习分类网络的发展历史
    杨辉三角
    【了解】贝塞尔曲线
    win10桌面点击事件蓝色边框处理
    try{}catch的隐藏(如何优雅的实现异常块)
    switch的一些思考(seitch与ifelse的区别)
    好看的控制台日志线
    Serializable和Externalizabl的异同
    java排序方式对比
    如何初始化Map,java
  • 原文地址:https://www.cnblogs.com/xiangism/p/2741128.html
Copyright © 2011-2022 走看看