首页 > 解决方案 > 如何在 C# 中为 WPF 在 JPG 上绘制矩形

问题描述

[![在此处输入图像描述][1]][1]我有一个包含一系列 jpg 的文件夹,这些是已转换为 jpg 的视频帧。我编写了一些代码来遍历它们并显示它们。

我正在尝试在 C# 的 JPG 图像上绘制一个绿色框。高度、宽度、XC 和 YC 都在一个 XML 中,我只是在其中访问每一帧的数据。我让它使用位图工作,但是要在 WPF 中显示它,我必须先将它转换为 bitmapImage。问题是它需要很长时间。我希望视频以 25 fps 的速度播放。所以所有的处理都需要在 40 毫秒内进行。现在,显示新图像需要 0.01 到 0.3 秒之间的任何时间。

这是我到目前为止的代码-

public void UpdateImage(string imageName, int[] boxData)
{


    // imageName is the file path the image
    Bitmap oldImage = new Bitmap(imageName);


    // if objects are detected
    if (boxData.Length != 0)
    {
        // transforms x and y cords to align box better to light
        int newXC = boxData[0] - (boxData[2] / 2);
        int newYC = boxData[1] - (boxData[3] / 2);

        // ensures cords are not negative
        if (newXC < 0)
            newXC = 0;
        if (newYC < 0)
            newYC = 0;

        // uses the DrawRectangleBorder to draw rectangles 
        Bitmap newImage = DrawRectangleBorder(oldImage, new Rectangle(new System.Drawing.Point(newXC, newYC), new System.Drawing.Size(boxData[2], boxData[3])), Color.Green);

        // converts Bitmap to BitmapImage
        using (MemoryStream memory = new MemoryStream())
        {
            newImage.Save(memory, ImageFormat.Png);
            memory.Position = 0;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memory;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
            ImportImage.Source = bitmapImage;
        }
    }

    else
    {
        Bitmap newImage = oldImage;

        // converts Bitmap to BitmapImage
        using (MemoryStream memory = new MemoryStream())
        {
            newImage.Save(memory, ImageFormat.Png);
            memory.Position = 0;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memory;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
            ImportImage.Source = bitmapImage;
        }
    }
}

DrawRectangleBorder 方法——

private static Bitmap DrawRectangleBorder(Bitmap image, Rectangle rectangle, Color colour)
{

    // makes new blank Bitmap from the old ones width and height
    Bitmap newBitmap = new Bitmap(image.Width, image.Height);

    // opens up the blank bit
    using (Graphics graphics = Graphics.FromImage(newBitmap))
        graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
            new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

    // what actually draws the rectangles
    for (Int32 x = rectangle.Location.X; x <= rectangle.Right && x < image.Width; x++)
        for (Int32 y = rectangle.Location.Y; y <= rectangle.Bottom && y < image.Height; y++)
            if (y == rectangle.Location.Y || y == rectangle.Bottom || x == rectangle.Location.X || x == rectangle.Right)
                newBitmap.SetPixel(x, y, colour);

    return newBitmap;
}

这是其中一张图片的样子,它们的分辨率为 640 x 480 - [1]:https ://i.stack.imgur.com/ZiocC.jpg 任何帮助都会很棒!

标签: c#.netwpfimage-processing

解决方案


您可以使用此 XAML 简化代码

<Canvas>
    <Image x:Name="ImportImage"/>
    <Path x:Name="ObjectBox"
          Width="{Binding ActualWidth, ElementName=ImportImage}"
          Height="{Binding ActualHeight, ElementName=ImportImage}"
          Stretch="None" Stroke="Green" StrokeThickness="1"/>
</Canvas>

使用这样的 UpdateImage 方法:

public void UpdateImage(string imagePath, int[] boxData)
{
    ImportImage.Source = new BitmapImage(new Uri(imagePath));

    var boxes = new GeometryGroup();

    for (int i = 0; i <= boxData.Length - 4; i += 4)
    {
        int width = boxData[i + 2];
        int height = boxData[i + 3];
        int x = boxData[i] - width / 2;
        int y = boxData[i + 1] - height / 2;

        boxes.Children.Add(new RectangleGeometry(new Rect(x, y, width, height)));
    }

    ObjectBox.Data = boxes;
}

推荐阅读