• 写了个类似按键精灵的找图类。方便大家做UI测试的时候可以用 dotNET界面


    在Delphi源码有个叫BitmapData的一个找图找色组件性能非常好效果也很给力.一直想用C#实现但是最初实现的性能实在太糟糕了. 找个图片基本都是6 秒以上. 后来经过自己改进开unsafe 用指针后速度有了比较大的提升基本满足了做模拟外挂或者做UI测试的时候图像判断。现在公布出来给大家参考下 如果有更好的性能提升优化请在讨论下面留言 不胜感激。

    目前只支持 24位的bmp 其他的就不支持了 源码在下面有时间可以自己改下  我机器配置如下:e31230 8G 找图片 在  1980 1080的图找 20*20的图片没设置背景透明色的情况下   100ms以内 算是满足做找图需求了。

    使用如下:

                //定义色差范围值

                BGR bgr = new BGR();
                bgr.B = 1;
                BitmapDataFinder big = new BitmapDataFinder("C:\\b.bmp");
                big.Name = "母图";
                BitmapDataFinder targ = new BitmapDataFinder("C:\\a1.bmp");
                targ.Name = "子图";

        可以对图片设置背景色.有时候子图 是有透明的地方的,这里用到  BackColor 设置一个颜色为透明色  颜色类型为BGR

                targ.BackColor=;


                Stopwatch watch = new Stopwatch();
                int x = 0, y = 0;
                watch.Start();
                bool b = big.Find(targ, bgr, ref x, ref y);
                watch.Stop();
                MessageBox.Show(watch.ElapsedMilliseconds.ToString() + "   " + x.ToString() + "," + y.ToString());

      /// <summary>
        /// 三色分量
        /// </summary>
        public struct BGR
        {
            public byte B { get; set; }
            public byte G { get; set; }
            public byte R { get; set; }
    
    
            public static bool operator ==(BGR c1, BGR c2)
            {
                return c1.R == c2.R && c1.B == c1.B && c1.G == c2.G;
    
            }
    
            public static bool operator !=(BGR c1, BGR c2)
            {
                return !(c1.R == c2.R && c1.B == c1.B && c1.G == c2.G);
            }
    
     
        }
    
        /// <summary>
        /// 图片快速搜索类(大图找小图)
        /// </summary>
        public class BitmapDataFinder
        {
            const int BD_BYTECOUNT = 3;
            /// <summary>
            /// 名字
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 位图宽度(象素)
            /// </summary>
            public int Width { get; private set; }
            /// <summary>
            /// 位图高度(象素)
            /// </summary>
            public int Height { get; private set; }
    
    
            private BGR _backColor;
            /// <summary>
            /// 背景颜色(BGR格式)
            /// </summary>
            public BGR BackColor { get { return _backColor; } set { _backColor = value; IsEnableBackColor = true; } }
            /// <summary>
            ///  对齐后每行数据宽度(字节)
            /// </summary>
            public int LineWidth { get; private set; }
            /// <summary>
            /// 对齐后每行数据多余宽度(字节)
            /// </summary>
            public int OffsetWidth { get; private set; }
            /// <summary>
            /// 位图数据长度
            /// </summary>
            public int Length { get; private set; }
            /// <summary>
            ///  缓冲区实际长度(目前未用到,和位图数据长度一致)
            /// </summary>
            public int BufSize { get; private set; }
    
            private byte[] _bits;
            /// <summary>
            /// 位图数据缓冲区
            /// </summary>
            public byte[] Bits { get { return _bits; } private set { _bits = value; } }
            /// <summary>
            /// 是否开启了背景色
            /// </summary>
            public bool IsEnableBackColor { get; set; }
    
            public BitmapDataFinder(string path)
            {
                if (!File.Exists(path))
                    throw new Exception(path + " 文件无法找到!");
                IniteData(new Bitmap(path));
            }
    
            public BitmapDataFinder(Bitmap bmp)
            {
                IniteData(bmp);
            }
    
            /// <summary>
            /// 初始化数据
            /// </summary>
            /// <param name="bmp"></param>
            private void IniteData(Bitmap bmp)
            {
                if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                {
                    throw new Exception("错误颜色格式只支持24位bmp");
                }
                BitmapData bitmapdata = bmp.LockBits(new Rectangle(new System.Drawing.Point(), bmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                try
                {
                    Width = bitmapdata.Width;
                    Height = bitmapdata.Height;
                    LineWidth = bitmapdata.Stride;
                    OffsetWidth = bitmapdata.Stride - bitmapdata.Width * BD_BYTECOUNT; //对齐后每行数据多余宽度(字节)
                    Length = bitmapdata.Stride * Height;  //位图数据长度
                    BufSize = Length; //缓冲区实际长度
                    int length = Length;
                    Bits = new byte[length];
                    Marshal.Copy(bitmapdata.Scan0, Bits, 0, length);
                }
                finally
                {
                    bmp.UnlockBits(bitmapdata);
                    bmp.Dispose();
                }
            }
    
    
            /// <summary>
            /// 获取指定坐标点颜色
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public BGR this[int x, int y]
            {
                get
                {
                    BGR c = new BGR();
                    if (x < 0 || (x >= this.Width) ||
                        (y < 0) || (y >= this.Height))
                    {
                        throw new Exception("索引越界错误");
                    }
                    else
                    {
                        //  c.B = Bits[(((this.Height - y - 1) * this.LineWidth) + x * BD_BYTECOUNT)];
                        int offset = y * this.LineWidth + x * BD_BYTECOUNT;
                        c.B = Bits[offset];
                        c.G = Bits[offset + 1];
                        c.R = Bits[offset + 2];
                    }
                    return c;
                }
            }
    
            /// <summary>
            /// 比对大图中某坐标是否存在小图
            /// </summary>
            /// <param name="bmp"></param>
            /// <param name="range"></param>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public unsafe bool Compare(BitmapDataFinder bmp, BGR range, byte* b1, byte* b2, int Left, int Top)
            {
                bool result;
                if (((Left + bmp.Width) > this.Width) || ((Top + bmp.Height) > this.Height))
                {
                    return false;
                }
                result = true;
                int offset1 = 0, offset2 = 0;
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        offset1 = (Top + y) * this.LineWidth + (Left + x) * BD_BYTECOUNT;
                        offset2 = y * bmp.LineWidth + x * BD_BYTECOUNT;
                        //如果背景颜色启用而且当前颜色等于背景色,则继续看下一个点
                        if (bmp.IsEnableBackColor && (*(b2 + offset2) == bmp.BackColor.B && *(b2 + offset2 + 1) == bmp.BackColor.G && *(b2 + offset2 + 2) == bmp.BackColor.R))
                            continue;
                        //颜色比较
                        if (!BGRCompareColor(*(b1 + offset1), *(b1 + offset1 + 1), *(b1 + offset1 + 2), *(b2 + offset2), *(b2 + offset2 + 1), *(b2 + offset2 + 2), range))
                        {
                            result = false;
                            break;
                        }
                    }
                    if (!result) break;
                }
                return result;
            }
    
            public unsafe bool Compare(BitmapDataFinder bmp, byte* b1, byte* b2, int Left, int Top)
            {
                bool result;
                if (((Left + bmp.Width) > this.Width) || ((Top + bmp.Height) > this.Height))
                {
                    return false;
                }
                result = true;
                int offset1 = 0, offset2 = 0;
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        offset1 = (Top + y) * this.LineWidth + (Left + x) * BD_BYTECOUNT;
                        offset2 = y * bmp.LineWidth + x * BD_BYTECOUNT;
    
                        //如果背景颜色启用而且当前颜色等于背景色,则继续看下一个点
                        if (bmp.IsEnableBackColor && (*(b2 + offset2) == bmp.BackColor.B && *(b2 + offset2 + 1) == bmp.BackColor.G && *(b2 + offset2 + 2) == bmp.BackColor.R))
                            continue;
                        //颜色比较 
                        if (*(b2 + offset2) != *(b1 + offset1) || *(b2 + offset2 + 1) != *(b1 + offset1 + 1) || *(b2 + offset2 + 2) != *(b1 + offset1 + 2))
                        {
                            result = false;
                            break;
                        }
    
                    }
                    if (!result) break;
                }
                return result;
            }
    
            /// <summary>
            /// 颜色比较
            /// </summary>
            /// <param name="c1"></param>
            /// <param name="c2"></param>
            /// <param name="range"></param>
            /// <returns></returns>
            public bool BGRCompareColor(BGR c1, BGR c2, BGR range)
            {
                return ((Math.Abs(c1.R - c2.R) <= range.R) && (Math.Abs(c1.G - c2.G) <= range.G) && (Math.Abs(c1.B - c2.B) <= range.B));
            }
    
            public bool BGRCompareColor(byte c1B, byte c1G, byte c1R, byte c2B, byte c2G, byte c2R, BGR range)
            {
                //B
                int C = c1B - c2B;
                if ((C > range.B) || (C < -range.B)) return false;
                //G
                C = c1G - c2G;
                if ((C > range.G) || (C < -range.G)) return false; ;
                //R
                C = c1R - c2R;
                if ((C > range.R) || (C < -range.R)) return false; ;            //
                return true;
    
            }
    
            /// <summary>
            /// 找图
            /// </summary>
            /// <param name="bmp"></param>
            /// <param name="range"></param>
            /// <param name="Left"></param>
            /// <param name="Top"></param>
            /// <returns></returns>
            public unsafe bool Find(BitmapDataFinder bmp, BGR range, ref int Left, ref int Top)
            {
                bool result = false;
                int x = 0;
                int y = 0;
                fixed (byte* b1 = &Bits[0])
                {
                    fixed (byte* b2 = &bmp.Bits[0])
                    {
                        for (y = 0; y + bmp.Height < this.Height; y++)
                        {
                            for (x = 0; x + bmp.Width < this.Width; x++)
                            {
                                if (Compare(bmp, range, b1, b2, x, y))
                                {
                                    result = true;
                                    break;
                                }
                            }
                            if (result)
                            {
                                break;
                            }
                        }
                    }
                }
                if (result)
                {
                    Left = x;
                    Top = y;
                }
                else
                {
                    Left = -1;
                    Top = -1;
                }
                return result;
            }
            public bool Find(BitmapDataFinder bmp, byte range)
            {
                int Left = 0, Top = 0;
                BGR b = new BGR();
                b.B = range;
                b.G = range;
                b.R = range;
                return Find(bmp, b, ref   Left, ref   Top);
            }
    
            public bool Find(BitmapDataFinder bmp, byte range, ref Point p)
            {
                int Left = 0, Top = 0;
                BGR b = new BGR();
                b.B = range;
                b.G = range;
                b.R = range;
                bool re = Find(bmp, b, ref   Left, ref   Top);
                p.X = Left;
                p.Y = Top;
                return re;
    
            }
            public bool Find(BitmapDataFinder bmp, BGR range)
            {
                int Left = 0, Top = 0;
    
                return Find(bmp, range, ref   Left, ref   Top);
            }
    
            public bool Find(BitmapDataFinder bmp, byte r, byte g, byte b)
            {
                int Left = 0, Top = 0;
                BGR range = new BGR();
                range.B = b;
                range.G = g;
                range.R = r;
                return Find(bmp, range, ref   Left, ref   Top);
            }
    
    
            public unsafe bool Find(BitmapDataFinder bmp, ref int Left, ref int Top)
            {
                bool result = false;
                int x = 0;
                int y = 0;
                fixed (byte* b1 = &Bits[0])
                {
                    fixed (byte* b2 = &bmp.Bits[0])
                    {
                        for (y = 0; y + bmp.Height < this.Height; y++)
                        {
                            for (x = 0; x + bmp.Width < this.Width; x++)
                            {
                                if (Compare(bmp, b1, b2, x, y))
                                {
                                    result = true;
                                    break;
                                }
                            }
                            if (result)
                            {
                                break;
                            }
                        }
                    }
                }
                if (result)
                {
                    Left = x;
                    Top = y;
                }
                else
                {
                    Left = -1;
                    Top = -1;
                }
                return result;
    
            }
    
            /// <summary>
            /// 枚举子图所有可能点
            /// </summary>
            /// <param name="bmp"></param>
            /// <param name="range"></param>
            /// <returns></returns>
            public unsafe List<Point> EnumImage(BitmapDataFinder bmp, BGR range)
            {
                List<Point> list = new List<Point>();
                int x = 0;
                int y = 0;
                fixed (byte* b1 = &Bits[0])
                {
                    fixed (byte* b2 = &bmp.Bits[0])
                    {
                        for (y = 0; y + bmp.Height < this.Height; y++)
                        {
                            for (x = 0; x + bmp.Width < this.Width; x++)
                            {
                                if (Compare(bmp, range, b1, b2, x, y))
                                {
                                    list.Add(new Point(x, y));
                                }
                            }
                        }
                    }
                }
                return list;
            }
    
            /// <summary>
            /// 保存为图片文件
            /// </summary>
            /// <param name="path"></param>
            public void SaveToBmp(string path)
            {
                SaveToBmp().Save(path);
            }
    
            /// <summary>
            /// 保存图片
            /// </summary>
            /// <returns></returns>
            public Bitmap SaveToBmp()
            {
                Bitmap bmp = new Bitmap(this.Width, this.Height);
                BitmapData bitmapdata = bmp.LockBits(new Rectangle(new System.Drawing.Point(), bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
                try
                {
                    Marshal.Copy(Bits, 0, bitmapdata.Scan0, Length);
                }
                finally
                {
                    bmp.UnlockBits(bitmapdata);
                }
                return bmp;
            }
    
    
            /// <summary>
            /// 屏幕截图
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <param name="width"></param>
            /// <param name="height"></param>
            /// <returns></returns>
            public static BitmapDataFinder CopyScreen(int x, int y, int width, int height)
            {
                //根据屏幕大小建立位图
                Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(x, y, 0, 0, new Size(width, height));
                }
                return new BitmapDataFinder(bitmap);
            }
    
    
        }
    

     代码下载

  • 相关阅读:
    ELK的学习与应用
    windows 常用命令
    Electron笔记
    C#基础
    IIS运行NetCore程序
    nuget打包
    web pack备忘
    基于并发订课系统的架构演变
    面试造核弹的童话
    Python3-接口自动化-11-使用join方法请求参数拼接,格式key1=value1&keys=value2....
  • 原文地址:https://www.cnblogs.com/jasondun/p/2647580.html
Copyright © 2020-2023  润新知