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的学习。

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

  • 相关阅读:
    hdu 4002 Find the maximum
    hdu 2837 坑题。
    hdu 3123
    zoj Treasure Hunt IV
    hdu 2053 Switch Game 水题一枚,鉴定完毕
    poj 1430 Binary Stirling Numbers
    hdu 3037 Saving Beans
    hdu 3944 dp?
    南阳oj 求N!的二进制表示最低位的1的位置(从右向左数)。
    fzu 2171 防守阵地 II
  • 原文地址:https://www.cnblogs.com/xiangism/p/2741128.html
Copyright © 2011-2022 走看看