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

  • 总结

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

    最后,欢迎拍砖。

    谢谢支持。

时间: 2024-10-10 07:43:37

C# 之屏幕找图的相关文章

触摸精灵实现找图功能

功能是实现区域模糊找图功能  脚本如下: function main() -- main函数,脚本播放时会执行该函数 mSleep(2000) -- 等待2秒后执行,目的是防止触摸精灵开启提示遮挡屏幕,也可在设置中设置关闭开启提示功能 -- 点击函数 appRun("com.tencent.xin");--运行微信,iOS的Bundle ID mSleep(2000); x, y = findImageInRegionFuzzy("/var/mobile/Applicatio

网摘-按键精灵屏幕找色原理分析

一.数据提取 位图其实可以看成是一个由象素组成的矩阵,找图找色可以看成是象素值的比对.很多新手在设计这类的程序时喜欢使用TBitmap.Canvas.Pixels属性,这个属性其实是对API函数GetPixel的封装,这个函数执行速度是很慢的,主要用来对位图象素进行偶尔的访问.而比对过程中需要对象素进行频繁的访问,造成程序运行缓慢.另外一种方法是使用TBitmap.ScanLine属性,利用它可以直接访问位图的数据.但是这些数据和当前位图的格式有关,主要是色深方面的问题,不同的色深会有不同格式的

AHK 找字找图,大漠调用实例演示[搬运][复制][拷贝][副本][备份]

;~  AHK 找字找图,大漠调用实例演示[搬运][复制][拷贝][副本][备份] ;~ https://www.autoahk.com/?p=16306;~ https://gitee.com/weiyunwps618/codes/t41vlkhpy0m3wr9568cua42;~ https://www.cnblogs.com/delphixx/p/11835278.html /* https://www.autohotkey.com/boards/viewtopic.php?t=17834

最近听说搞脚本挺爽的 弄了个按键精灵的找图找色

首先你需要下载个按键精灵的软件.如下http://www.anjian.com/ 下好后就打开按键精灵,首先新建一个空白脚本,然后找到抓取按钮. 随便找张图来找色 比如如上这张,用抓取按钮选择右键找到色素点,如#c10b2a 然后将该值放到颜色/图形命令去 在图形找色这里,还有找图功能,其实原理都差不多,都是通过周边像素点的色值来找到符合这个值得点,这样就能找到所选的数据. 当你找到你想得到的句柄(windows的某些你想要获取的窗口)时,就可以通过找色或找图去设置你自己所要的功能.

C#实现按键精灵的&#39;找图&#39; &#39;找色&#39; &#39;找字&#39;的功能

背景:游戏辅助功能通常使用按键精灵编写脚本,按键精灵的最大卖点就是能够找到画面中字,图,色,这对于模拟用户鼠标操作至关重要,这能找到道具,找到血量,实现自动打怪,自动补血,自动买卖道具,博主闲来无聊,看到一款按键精灵实现的辅助,于是乎想用WPF也写一款辅助工具,实现其核心的找图找色等功能.博主测试,对于背景复杂多变的画面,找不变图的成功率达到100%,找带透明的图,比如文字,能达到90%以上.默认您已经知道一个颜色值由argb构成,每个值范围都是0~255.网上发现不少人询问过该问题,几乎没有比

C#实现按键精灵的“找图”“找色”“找字”的功能

背景:游戏辅助功能通常使用按键精灵编写脚本,按键精灵的最大卖点就是能够找到画面中字,图,色,这对于模拟用户鼠标操作至关重要,这能找到道具,找到血量,实现自动打怪,自动补血,自动买卖道具,博主闲来无聊,看到一款按键精灵实现的辅助,于是乎想用WPF也写一款辅助工具,实现其核心的找图找色等功能.博主测试,对于背景复杂多变的画面,找不变图的成功率达到100%,找带透明的图,比如文字,能达到90%以上.默认您已经知道一个颜色值由argb构成,每个值范围都是0~255.网上发现不少人询问过该问题,几乎没有比

大漠&amp;易语言 找字、找图

找字 .版本 2.支持库 dm dm.SetPath ()dm.SetDict (0, “字库.txt”)hwnd = dm.GetMousePointWindow ()dm.BindWindow (hwnd, “normal”, “normal”, “normal”, 0)返回文本 = dm.Ocr (0, 0, 1280, 1024, “000000-000000”, 1)dm.UnBindWindow () 找图 dm.SetPath () dm.FindPicE (0, 0, 1280,

易语言怎样写双线程?一个线程循环找图。一个线程循环按键F2。

易语言怎样写双线程? 一个线程循环找图.一个线程循环按键F2. // .程序集变量 参数, 整数型 .程序集变量 线程句柄1, 整数型 .程序集变量 线程句柄2, 整数型 启动线程 (&子程序1, 参数,线程句柄1) 启动线程 (&子程序2, ,线程句柄2) // .子程序 子程序1 .参数 参数1, 整数型 信息框 (参数1, 0, ) 信息框 (“这是线程1的例子”, 0, ) // .子程序 子程序2 信息框 (“这是线程2的例子”, 0, ) // // 注意: 凡调用到COM接口

Q语言 我的命令库《通用找图》之后台找字函数源码

'=====================找字命令===============================Function 找字B(字符串,字号,点X1, 点Y1, 点X2, 点Y2)// 后台找图Dim iZB, XyXY = Plugin.Bkgnd.FindWordShape(Hwnd,clng(点X1), clng(点Y1), clng(点X2), clng(点Y2), 字符串, "", Cint(字号), 0,0.9)iZB = InStr(XY, "|&q