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

在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);

        }





    }

 代码下载

你可能感兴趣的:(UI)