转载

C# 之屏幕找图

  • 引言

最近,由于工作上的某些原因,又要写类似于外挂的程序,又要用到一个屏幕找图功能,很多程序(eg:按键精灵)都提供了类似的功能,其实在这之前,我也查找过很多类似的C#方法,因为之前有一个试过没有用得起,所以最后就放弃了,知道现在都是使用的自己写的一个,相对来说,除了效率比较慢,没有太大的问题。不过就是由于效率不高,后面又想了其他的一些解决办法。

  • 基础+贴代码。

因为是一些图片处理和操作,所以必不可少的会用到C# GDI+的一些基本知识,对于这个网上应该也有很多,大家可以拿来学习和参考。

再者,其实细细想一下,其实应该很简单,为什么呢,因为就是一个一个像素的比较,比较颜色差异,没有差异就通过,有差异,就继续查找,知道找到必须要,且完全匹配就OK。

于是乎有了下面的代码。1.0

// 基础代码和调用代码 (注释基本,略,后面又没有添加,多多包涵)

C# 之屏幕找图
 1 public class ImageManager  2     {  3         public static Point Compare(Bitmap bigImage, Bitmap smallImage)  4         {  5             for (int i = 0; i < bigImage.Width; i++)  6             {  7                 for (int j = 0; j < bigImage.Height; j++)  8                 {  9                     Color c1 = bigImage.GetPixel(i, j); 10                     Color c2 = smallImage.GetPixel(0, 0); 11  12                     // 颜色相等,且没有超出边界 13                     if (Compare(c1, c2) && bigImage.Width >= (i + smallImage.Width) && bigImage.Height >= (j + smallImage.Height)) 14                     { 15                         bool iscontinue = false; 16                         for (int x = 0; x < smallImage.Width; x++) 17                         { 18                             for (int y = 0; y < smallImage.Height; y++) 19                             { 20                                 Color c3 = smallImage.GetPixel(x, y); 21                                 Color c4 = bigImage.GetPixel(i + x, j + y); 22                                 if (!Compare(c3, c4)) 23                                 { 24                                     iscontinue = true; 25                                     break; 26                                 } 27                             } 28  29                             if (iscontinue) 30                             { 31                                 break; 32                             } 33                         } 34  35                         if (!iscontinue) 36                         { 37                             return new Point(i, j); 38                         } 39                     } 40                 } 41             } 42  43             return new Point(-1, -1); 44         } 45  46         private static bool Compare(Color c1, Color c2) 47         { 48             if (c1.A == c2.A && c1.R == c2.R && c1.B == c2.B && c1.G == c2.G) 49             { 50                 return true; 51             } 52  53             return false; 54         } 55     }
C# ImageManager 1.0
C# 之屏幕找图
 1     /// <summary>  2         /// 得到指定图片顶点  3         /// </summary>  4         /// <param name="picName">图片名称</param>  5         private Point GetPicturePoint(string picName)  6         {  7             Bitmap image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);  8             Graphics imgGraphics = Graphics.FromImage(image);  9  10             //设置截屏区域  11             imgGraphics.CopyFromScreen(0, 0, 0, 0, new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)); 12  13             // 然后从截屏图片中查找指定图片 14             string taskImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image", picName); 15             Image img = Image.FromFile(taskImagePath); 16  17             var result = ImageManager.Compare(CloseImg(image), CloseImg(img)); 18  19             return result; 20         } 21  22         private Bitmap CloneImg(Image img) 23         { 24             using (MemoryStream mostream = new MemoryStream()) 25             { 26                 Bitmap bmp = new Bitmap(img); 27                 bmp.Save(mostream, System.Drawing.Imaging.ImageFormat.Jpeg);//将图像以指定的格式存入缓存内存流 28                 byte[] bt = new byte[mostream.Length]; 29                 mostream.Position = 0;//设置流的初始位置 30                 mostream.Read(bt, 0, Convert.ToInt32(bt.Length)); 31  32                 return bmp; 33             } 34         }
ImageManager 调用方法

由于效率不敢恭维,没办法,又想其他的法子吧,于是乎想到了多线程。。

  • 多线程处理,效率没啥子提升感觉。

由于代码的处理方式,造成了,循环太多,处理的比较的次数很多,运算量大。。

多线程怎么处理呢,于是想到了,把整个屏幕分成很多块小图片,这样,用小图片和要查找的图片进行比较然后得到最后的结果。但是问题来了,如果,图片正好在中间怎么办。于是就把小图片,朵切割一点,多切割,需要查找的图片的宽度和高度。

于是写成了代码,如下:

C# 之屏幕找图
  1 public class ImageManager   2     {   3         private static List<Point> result = new List<Point>();   4    5         public static event Action<int, Image> DoPic;   6    7         private static int width = 0;   8    9         private static int height = 0;  10   11         /// <summary>  12         /// 多线程找图  13         /// </summary>  14         /// <param name="bigImage"></param>  15         /// <param name="smallImage"></param>  16         /// <returns></returns>  17         public static Point ThreadCompare(Bitmap bigImage, Bitmap smallImage)  18         {  19             result = new List<Point>();  20             // 先拆分大图成为16个小图片,每个小图片都需要加上smallImage的长宽组成一个新图片  21             // 需要16个线程来完成。  22             width = (int)Math.Ceiling(bigImage.Width / 4.0);  23             height = (int)Math.Ceiling(bigImage.Height / 4.0);  24             int maxWidth = width + smallImage.Width;  25             int maxHeight = height + smallImage.Height;  26             int index = 0;  27             for (int i = 0; i < 4; i++)  28             {  29                 for (int j = 0; j < 4; j++)  30                 {  31                     Bitmap bitMap = null;  32                     if (i == 3 && j == 3)  33                     {  34                         bitMap = new Bitmap(width, height);  35                     }  36                     else if (j == 3)  37                     {  38                         bitMap = new Bitmap(maxWidth, height);  39                     }  40                     else if (i == 3)  41                     {  42                         bitMap = new Bitmap(width, maxWidth);  43                     }  44                     else  45                     {  46                         bitMap = new Bitmap(maxWidth, maxHeight);  47                     }  48   49                     Graphics resultG = Graphics.FromImage(bitMap);  50                     resultG.DrawImage(bigImage, new Rectangle(0, 0, bitMap.Width, bitMap.Height), new Rectangle(i * width, j * height, bitMap.Width, bitMap.Height), GraphicsUnit.Pixel);  51                     resultG.Dispose();  52   53                     if (DoPic != null)  54                     {  55                         DoPic(index, CloneImg(bitMap));  56                     }  57   58                     ThreadPool.QueueUserWorkItem(new WaitCallback(CompareThread), new object[] { bitMap, CloneImg(smallImage), i, j });  59                     index++;  60                 }  61             }  62   63             while (result.Count != 16)  64             {  65                 Thread.Sleep(50);  66             }  67   68             var point = new Point(-1, -1);  69             if (result.Exists(p => p.X >= 0))  70             {  71                 point = result.Find(a => a.X >= 0);  72             }  73   74             return point;  75         }  76   77         public static Point Compare(Bitmap bigImage, Bitmap smallImage)  78         {  79             for (int i = 0; i < bigImage.Width; i++)  80             {  81                 for (int j = 0; j < bigImage.Height; j++)  82                 {  83                     Color c1 = bigImage.GetPixel(i, j);  84                     Color c2 = smallImage.GetPixel(0, 0);  85   86                     // 颜色相等,且没有超出边界  87                     if (Compare(c1, c2) && bigImage.Width >= (i + smallImage.Width) && bigImage.Height >= (j + smallImage.Height))  88                     {  89                         bool iscontinue = false;  90                         for (int x = 0; x < smallImage.Width; x++)  91                         {  92                             for (int y = 0; y < smallImage.Height; y++)  93                             {  94                                 Color c3 = smallImage.GetPixel(x, y);  95                                 Color c4 = bigImage.GetPixel(i + x, j + y);  96                                 if (!Compare(c3, c4))  97                                 {  98                                     iscontinue = true;  99                                     break; 100                                 } 101                             } 102  103                             if (iscontinue) 104                             { 105                                 break; 106                             } 107                         } 108  109                         if (!iscontinue) 110                         { 111                             return new Point(i, j); 112                         } 113                     } 114                 } 115             } 116  117             return new Point(-1, -1); 118         } 119  120         private static void CompareThread(object obj) 121         { 122             object[] objs = obj as object[]; 123             Bitmap bigImage = objs[0] as Bitmap; 124             Bitmap smallImage = objs[1] as Bitmap; 125             int indexI = Convert.ToInt32(objs[2]); 126             int indexJ = Convert.ToInt32(objs[3]); 127             bool isbreak = false; 128             Point p = new Point(-1, -1); 129             for (int i = 0; i < bigImage.Width; i++) 130             { 131                 for (int j = 0; j < bigImage.Height; j++) 132                 { 133                     Color c1 = bigImage.GetPixel(i, j); 134                     Color c2 = smallImage.GetPixel(0, 0); 135  136                     // 颜色相等,且没有超出边界 137                     if (Compare(c1, c2) && bigImage.Width >= (i + smallImage.Width) && bigImage.Height >= (j + smallImage.Height)) 138                     { 139                         bool iscontinue = false; 140                         for (int x = 0; x < smallImage.Width; x++) 141                         { 142                             for (int y = 0; y < smallImage.Height; y++) 143                             { 144                                 Color c3 = smallImage.GetPixel(x, y); 145                                 Color c4 = bigImage.GetPixel(i + x, j + y); 146                                 if (!Compare(c3, c4)) 147                                 { 148                                     iscontinue = true; 149                                     break; 150                                 } 151                             } 152  153                             if (iscontinue) 154                             { 155                                 break; 156                             } 157                         } 158  159                         if (!iscontinue) 160                         { 161                             isbreak = true; 162                             p = new Point(i + indexI * width, j + indexJ * height); 163                             break; 164                         } 165                     } 166                 } 167  168                 if (isbreak) 169                 { 170                     break; 171                 } 172             } 173  174             result.Add(p); 175         } 176  177         private static bool Compare(Color c1, Color c2) 178         { 179             if (c1.A == c2.A && c1.R == c2.R && c1.B == c2.B && c1.G == c2.G) 180             { 181                 return true; 182             } 183  184             return false; 185         } 186  187         private static Bitmap CloneImg(Image img) 188         { 189             using (MemoryStream mostream = new MemoryStream()) 190             { 191                 Bitmap bmp = new Bitmap(img); 192                 bmp.Save(mostream, System.Drawing.Imaging.ImageFormat.Jpeg);//将图像以指定的格式存入缓存内存流 193                 byte[] bt = new byte[mostream.Length]; 194                 mostream.Position = 0;//设置留的初始位置 195                 mostream.Read(bt, 0, Convert.ToInt32(bt.Length)); 196  197                 return bmp; 198             } 199         } 200     }
ImageManager 2.0

终于支持多线程了,然后测试了一下,效率略有增加,不过没有太大的感觉。但是用别人的工具,感觉特别快,因为软件上面写的50,60毫秒,我就想啊,到底是哪里拖慢了速度呢。。。当然,没有想到。所以这里就抛砖引玉了。。。

  • 总结

博客园的编辑器,每次我都感觉自己不会用,别人写的文章,编辑出来效果杠杠的,为什么我这个不行呢,感觉有点坑。

最后,欢迎拍砖。

谢谢支持。

正文到此结束
Loading...