Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从屏幕捕获图像并获取颜色_C# - Fatal编程技术网

C# 从屏幕捕获图像并获取颜色

C# 从屏幕捕获图像并获取颜色,c#,C#,我正在制作一个程序,它可以捕捉屏幕上的一个小区域,如果图像上有与目标颜色匹配的颜色,它就会运行。我的程序按以下顺序运行: 从屏幕上的特定区域获取图像 保存到文件夹 使用CountPixel检测任何目标颜色 但是,在我单击按钮5两次(不是双击)后,它会通过下面一行的异常: b、 保存(@“C:\Applications\CaptureImage000.jpg”,ImageFormat.Jpeg) 例外情况: 类型的未处理异常 中出现“System.Runtime.InteropServices.E

我正在制作一个程序,它可以捕捉屏幕上的一个小区域,如果图像上有与目标颜色匹配的颜色,它就会运行。我的程序按以下顺序运行:

  • 从屏幕上的特定区域获取图像

  • 保存到文件夹

  • 使用
    CountPixel
    检测任何目标颜色 但是,在我单击
    按钮5
    两次(不是双击)后,它会通过下面一行的异常:

    b、 保存(@“C:\Applications\CaptureImage000.jpg”,ImageFormat.Jpeg)

  • 例外情况:

    类型的未处理异常 中出现“System.Runtime.InteropServices.ExternalException” System.Drawing.dll

    其他信息:GDI中发生一般错误+

    我的问题是:

  • 如何修复此异常
  • 我想使用另一种方法来代替
    CountPixel()
    ,以提高性能,因为我只需要检测一种目标颜色即可升高事件
  • 第二步很麻烦。我想知道我是否可以跳过它,用另一种方式调用:
    (@“C:\Applications\CaptureImage000.jpg”,ImageFormat.Jpeg)
    ,因为使用这个长字符串不舒服,并且在尝试使用
    GetPixel
    时会出现错误,。。。或者将其添加到互联网上的“价值示例”代码中进行改进

    private int CountPixels(Bitmap bm, Color target_color)
    {
        // Loop through the pixels.
        int matches = 0;
        for (int y = 0; y < bm.Height; y++)
        {
            for (int x = 0; x < bm.Width; x++)
            {
                if (bm.GetPixel(x, y) == target_color) matches++;
            }
        }
        return matches;
    }
    private Bitmap CapturedImage(int x, int y)
    {
        Bitmap b = new Bitmap(XX, YY);
    
    
        Graphics g = Graphics.FromImage(b);
        g.CopyFromScreen(x, y, 0, 0, new Size(XX, YY));
    
        b.Save(@"C:\Applications\CaptureImage000.jpg", ImageFormat.Jpeg);
    
        /* Run 3 line below will lead to question 1 - through exception
        Bitmap bm = new Bitmap(@"C:\Applications\CaptureImage000.jpg");
        int black_pixels = CountPixels(b, Color.FromArgb(255, 0, 0, 0));
        textBox3.Text = black_pixels + " black pixels";
        */
    
        return b;
    }
    private void button5_Click(object sender, EventArgs e)// Do screen cap
    {
        Bitmap bmp = null;
        bmp = CapturedImage(X0, Y0);
    }
    
    private int CountPixels(位图bm、颜色目标\u颜色)
    {
    //循环通过像素。
    int匹配=0;
    对于(int y=0;y

  • [编辑]今晚与OP合作完成了这项工作,做了一些改进 现在,这可以解释机器的端点,并通过使用Color.ToArgb()函数将颜色转换为整数来正确比较颜色

    下面的代码将起作用,为了清晰起见,我添加了注释,并为您提供了一些选项。我在没有IDE的情况下编写了代码,但我相信它很好

    在以下两种情况下,只需保留位图的句柄,无需保存并重新打开,无论是否需要副本

    CapturedImage函数的异常问题和改进 选项A(推荐)

    不要保存位图,您已经有了一个句柄,图形对象只是修改了BMP。只需保留此函数的以下代码,它就可以正常工作,而无需对其他选项之一进行注释

    代码和其他选项:

        private Bitmap CapturedImage(Bitmap bm, int x, int y)
        {
            Bitmap b = new Bitmap(XX, YY);
    
            Graphics g = Graphics.FromImage(b);
            g.CopyFromScreen(x, y, 0, 0, new Size(XX, YY));
    
    
            //option B - If you DO need to keep a copy of the image use PNG and delete the old image
            /*
            try
            {
                if(System.IO.File.Exists(@"C:\Applications\CaptureImage.png"))
                {
                    System.IO.File.Delete(@"C:\Applications\CaptureImage.png");
                }
                b.Save(@"C:\Applications\CaptureImage.png", ImageFormat.Png);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("There was a problem trying to save the image, is the file in open in another program?\r\nError:\r\n\r\n" + ex.Message);
            }
            */
    
            //option C - If you DO need to keep a copy of the image AND keep all copies of all images when you click the button use PNG and generate unique filename
            /*
            int id = 0;
            while(System.IO.File.Exists(@"C:\Applications\CaptureImage" + id.ToString().PadLeft('0',4) + ".png"))
            {
                //increment the id until a unique file name is found
                id++;
            }
            b.Save(@"C:\Applications\CaptureImage" + id.ToString().PadLeft('0',4) + ".png", ImageFormat.Png);
            */
    
    
            int black_pixels = CountPixels(b, Color.FromArgb(255, 0, 0, 0));
            textBox3.Text = black_pixels + " black pixels";
    
            return b;
        }
    
    现在对于CountPixels函数,您有3个选项,但实际上,您有一个非常实心的选项,所以我省略了其他选项

    这将锁定BMP中的位,使用编组将数据复制到数组中,并以非常非常快的速度扫描数组中的数据,您甚至可能不需要删除计数。如果仍然要删除计数,只需在其递增matches变量的正下方添加“return 1;”

    CountPixels函数的速度问题和改进
    private int CountPixels(位图bm、颜色目标\u颜色)
    {
    int匹配=0;
    位图bmp=(位图)bm.Clone();
    BitmapData bmpDat=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
    int size=bmpDat.Stride*bmpDat.Height;
    字节[]子字节=新字节[大小];
    System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0,subPx,0,size);
    //如果没有alpha通道,请将4(ARGB)更改为3(RGB),这适用于32bpp图像
    //三值运算符检查机器的端部,并将像素颜色组织为A、R、G、B或B、G、R、A(小端部反转);
    Color temp=BitConverter.IsLittleEndian?Color.FromArgb(subPx[i+2],subPx[i+1],subPx[i]):Color.FromArgb(subPx[i+1],subPx[i+2],subPx[i+3]);
    对于(inti=0;i
    最后,使用相同的函数,但允许公差百分比
    private int CountPixels(位图bm、颜色目标\u颜色、浮点公差百分比)
    {
    int匹配=0;
    位图bmp=(位图)bm.Clone();
    BitmapData bmpDat=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
    int size=bmpDat.Stride*bmpDat.Height;
    字节[]子字节=新字节[大小];
    System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0,subPx,0,size);
    对于(int i=0;i    private int CountPixels(Bitmap bm, Color target_color)
        {
            int matches = 0;
            Bitmap bmp = (Bitmap)bm.Clone();
            BitmapData bmpDat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
            int size = bmpDat.Stride * bmpDat.Height;
            byte[] subPx = new byte[size];
            System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0, subPx, 0, size);
    
            //change the 4 (ARGB) to a 3 (RGB) if you don't have an alpha channel, this is for 32bpp images
    
            //ternary operator to check endianess of machine and organise pixel colors as A,R,G,B or B,G,R,A (little endian is reversed);
            Color temp = BitConverter.IsLittleEndian ? Color.FromArgb(subPx[i + 2], subPx[i + 1], subPx[i]) : Color.FromArgb(subPx[i + 1], subPx[i + 2], subPx[i + 3]);
            for (int i = 0; i < size; i += 4 ) //4 bytes per pixel A, R, G, B
            {
                if(temp.ToArgb() == target_color.ToArgb())
                {
                    matches++;
                }
            }
            System.Runtime.InteropServices.Marshal.Copy(subPx, 0, bmpDat.Scan0, subPx.Length);
            bmp.UnlockBits(bmpDat);
    
            return matches;
        }
    
        private int CountPixels(Bitmap bm, Color target_color, float tolerancePercent)
        {
            int matches = 0;
            Bitmap bmp = (Bitmap)bm.Clone();
            BitmapData bmpDat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
            int size = bmpDat.Stride * bmpDat.Height;
            byte[] subPx = new byte[size];
            System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0, subPx, 0, size);
    
            for (int i = 0; i < size; i += 4 )
            {
                byte r = BitConverter.IsLittleEndian ? subPx[i+2] : subPx[i+3];
                byte g = BitConverter.IsLittleEndian ? subPx[i+1] : subPx[i+2];
                byte b = BitConverter.IsLittleEndian ? subPx[i] : subPx[i+1];
                float distancePercent = (float)Math.Sqrt(
                    Math.Abs(target_color.R-r) + 
                    Math.Abs(target_color.G-g) + 
                    Math.Abs(target_color.B-b)
                ) / 7.65f;
    
                if(distancePercent < tolerancePercent)
                {
                    matches++;
                }
            }
            System.Runtime.InteropServices.Marshal.Copy(subPx, 0, bmpDat.Scan0, subPx.Length);
            bmp.UnlockBits(bmpDat);
    
            return matches;
        }