你的位置:首页 > ASP.net教程

[ASP.net教程]C# 之屏幕找图


  • 引言

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

  • 基础+贴代码。

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

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

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

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

 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
 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 调用方法

  

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

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

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

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

    于是写成了代码,如下:

 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毫秒,我就想啊,到底是哪里拖慢了速度呢。。。当然,没有想到。所以这里就抛砖引玉了。。。

  • 总结

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

    最后,欢迎拍砖。

    谢谢支持。