【问题标题】:Convert Graphics object to Bitmap将图形对象转换为位图
【发布时间】:2015-06-28 14:49:24
【问题描述】:

我的图形对象确实存在以下问题。

编辑:

我确实有一个图片框图像 (imageRxTx),它是来自相机的实时流。我在绘画事件中所做的是在图像 imageRxTx 顶部绘制一些线条(下面的代码中未显示)。到目前为止,这没有问题。

现在我需要检查 imageRxTx 中的圆圈,因此我必须使用需要位图作为参数的方法 ProcessImage()。不幸的是,我没有位图图像,而是我的 imageRxTx 的句柄 (hDC)

问题:如何从我的图形对象中获取 imageRxTx 并将其“转换”为我需要在方法 ProcessImage(Bitmap bitmap)?需要在绘画事件中不断调用此方法,以检查我的相机 (imageRxTx) 的实时流。

这是我的代码:

    private void imageRxTx_paint(object sender, PaintEventArgs e)
    {
        var settings = new Settings();

        // Create a local version of the graphics object for the PictureBox.
        Graphics Draw = e.Graphics;
        IntPtr hDC = Draw.GetHdc(); // Get a handle to image_RxTx.           

        Draw.ReleaseHdc(hDC); // Release image_RxTx handle.


        //Here I need to send the picturebox_image 'image_RxTx' to ProcessImage as Bitmap
        AForge.Point center = ProcessImage( ?....? );    
    }


    // Check for circles in the bitmap-image
    private AForge.Point ProcessImage(Bitmap bitmap)
    {
        //at this point I should read the picturebox_image 'image_RxTx'
        ...

视频图像在此更新:

    private void timer1_Elapsed(object sender, EventArgs e)
    {
        // If Live and captured image has changed then update the window
        if (PIXCI_LIVE && LastCapturedField != pxd_capturedFieldCount(1))
        {
            LastCapturedField = pxd_capturedFieldCount(1);
            image_RxTx.Invalidate();
        }
    }

【问题讨论】:

    标签: c# image graphics bitmap


    【解决方案1】:

    Graphics.CopyFromScreen 方法可能是您正在寻找的。

    var rect = myControl.DisplayRectangle;
    var destBitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb);
    using (var gr = Graphics.FromImage(destBitmap))
    {
        gr.CopyFromScreen(myControl.PointToScreen(new Point(0, 0)), new Point(0, 0), rect.Size);
    }
    

    【讨论】:

    • 是的,这可以工作,但我在保存 destBitmap 时只得到一个白色图像。也许它在实施中做错了什么。我的代码是:// Create a bitmap from the Graphics object var rect = image_RxTx.DisplayRectangle; var destBitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb); using (var gr = Graphics.FromImage(destBitmap)) { gr.CopyFromScreen(image_RxTx.PointToScreen(new Point(0, 0)), new Point(0, 0), rect.Size); } AForge.Point center = ProcessImage(destBitmap);
    • 我可以为“myControl”使用图片框图像吗?
    • 我认为问题出在这里: IntPtr hDC = Draw.GetHdc(); // 获取 image_RxTx 的句柄。我需要使用此句柄并将其转换为位图图像,但如何?
    • 如果你只得到一个白色的图像,那么你的控件可能还没有被绘制到屏幕上。您的事件处理程序可能在操作系统已填充背景颜色但尚未绘制图像时触发。请注意,操作系统不会将控件的位图“保存”在屏幕上以外的任何地方。如果您的控件被另一个窗口挡住了(如果您运行的调试器不断弹出到前台,这可能会出现问题!),那么您必须重新绘制它才能抓住它。
    【解决方案2】:

    正如标题所示,您的主要问题是对Graphics 对象的(常见)误解。

    到目前为止,我可以毫无问题地绘制到我的图形对象

    • 不! 'Graphics' 对象包含任何图形。它只是用于将图形绘制到相关 Bitmap 上的工具。所以你根本不会画到 Graphics 对象上;你用它来绘制imageRxTx,不管那是什么,可能是一些ControlForm的表面..

    • 这一行使用了Bitmapconstructor这种经常令人困惑且无用的格式:


    Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height, Draw); 
    

    最后一个参数是几乎没有;它的唯一功能是复制Dpi 设置。特别是它不会克隆或复制“Draw”中的任何内容,正如您现在所知,Graphics 对象无论如何都没有,也没有任何其他设置。所以是的,bmp Bitmap 在那之后仍然是空的。

    如果你想绘制到bmp,你需要使用一个实际绑定到它的Graphics对象:

    using (Graphics G = Graphics.FromImage(bmp)
    {
       // draw now..
       // to draw an Image img onto the Bitmap use
       G.DrawImage(img, ...); 
       // with the right params for source and destination!
    }
    

    不会Paint 事件中发生!但是对于您真正想要做什么,所有准备代码都不清楚。你应该解释一下什么是绘图的来源,什么是目标!

    如果你想把你画的东西放到 image_RxTx 进入 Bitmap 你可以使用这个方法somwhere outside (!)Paint 事件:

    Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height);
    image_RxTx.DrawToBitmap(bmp, image_RxTx.ClientRectangle);
    

    这将使用Paint 事件将控件绘制到Bitmap。并不是说结果包括整个 PictureBoxBackgroundImageImage 表面绘图!

    更新:要获取PictureBox组合内容,即Image 和您在表面上绘制的内容,您应该使用上面的代码(最后两行)在Timer Tick 事件中,紧跟在触发Paint 事件的行之后。 (你没有向我们展示这是如何发生的。)你不能把它放在Paint 事件本身,因为它会使用Paint 事件,因此会导致无限循环!

    【讨论】:

    • 感谢您的详细解释..!我编辑了我的问题以进行澄清。我需要的是我的image_RxTx(源图片框)的位图作为ProcessImage(Bitmap)方法的输入参数。请也查看我的编辑 - 谢谢。
    • 好的,我已经更新了答案。 Paint 事件是如何调用的?您在某处有 Invalidate() 还是在相机代码中?我希望视频实际上是在 PictureBox 中,而不仅仅是覆盖。你能做一个屏幕复制吗?
    • Paint 事件是在程序开始时在 InitializeComponent() 中生成的,因此在启动程序后会不断调用。 - 嗯,这没有意义。问题是它什么时候调用? (Paint 通常由系统调用,当它需要重新绘制窗口时或由您的代码调用,例如,当要绘制的内容发生变化时,例如对象已移动..
    • 啊,有道理。所以你插入两行,可能还有第三行用于保存或在 Invalidate 之后立即调用你的方法。哦,由于这种情况经常发生,我猜你实际上应该将创建位图的第一行移动到 InitializeComponent() 中并重用相同的位图,这样你就不会浪费时间一直创建它,也不会浪费 GDI 资源不处理所有这些位图.. 毕竟它们都将具有相同的大小。
    • 完美的TaW..!这是最后的解决方案。非常感谢您的帮助..!
    猜你喜欢
    • 2010-12-04
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多