最近,由于工作上的某些原因,又要写类似于外挂的程序,又要用到一个屏幕找图功能,很多程序(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 }
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 }
由于效率不敢恭维,没办法,又想其他的法子吧,于是乎想到了多线程。。
由于代码的处理方式,造成了,循环太多,处理的比较的次数很多,运算量大。。
多线程怎么处理呢,于是想到了,把整个屏幕分成很多块小图片,这样,用小图片和要查找的图片进行比较然后得到最后的结果。但是问题来了,如果,图片正好在中间怎么办。于是就把小图片,朵切割一点,多切割,需要查找的图片的宽度和高度。
于是写成了代码,如下:
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 }
终于支持多线程了,然后测试了一下,效率略有增加,不过没有太大的感觉。但是用别人的工具,感觉特别快,因为软件上面写的50,60毫秒,我就想啊,到底是哪里拖慢了速度呢。。。当然,没有想到。所以这里就抛砖引玉了。。。
博客园的编辑器,每次我都感觉自己不会用,别人写的文章,编辑出来效果杠杠的,为什么我这个不行呢,感觉有点坑。
最后,欢迎拍砖。
谢谢支持。
新闻热点
疑难解答