How to draw/overlay an image file to a bitmap image? - c#

I have a video feed from a Kinect sensor hosted by an image stored as a bitmap. My question is how do I overlay an image, for example a .png on to the video feed.
The video feed is shown like show below as bitmap source, I know how to draw a line to the bitmap but how do I draw an image from resources to the it?
KinectVideo.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96,
PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel);
Below is a mock up of what I'm trying to achieve by placing the image over the video feed:
Updated implementation of drawing method,I don't think this is the correct implementation also I'm getting invalid argument error when adding image path to .DrawImage:
void myKinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame == null) return;
byte[] colorData = new byte[colorFrame.PixelDataLength];
colorFrame.CopyPixelDataTo(colorData);
KinectVideo.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96,
PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel);
Rect destRect2;
//drawing image overlay to video feed
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel),
new Rect(new Size(colorFrame.Width, colorFrame.Height)));
drawingContext.DrawImage("Images/boxbag.jpg", destRect2);
drawingContext.Close();
var mergedImage = new RenderTargetBitmap(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Pbgra32);
mergedImage.Render(drawingVisual);
KinectVideo.Source = mergedImage;
}
}

To create merged image you can use DrawingContext that gives you methods like DrawText or DrawImage and then render it using RenderTargetBitmap.Render:
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel),
new Rect(new Size(colorFrame.Width, colorFrame.Height)));
var overlayImage = new BitmapImage(new Uri("Images/boxbag.jpg"));
drawingContext.DrawImage(overlayImage,
new Rect(x, y, overlayImage.Width, overlayImage.Height));
drawingContext.Close();
var mergedImage = new RenderTargetBitmap(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Pbgra32);
mergedImage.Render(drawingVisual);
KinectVideo.Source = mergedImage;

If you just want display an Image on top of another UI control, then you can either just declare one after the other UI elements, or set the Panel.ZIndex property:
<Grid>
<Border Background="Black" />
<Image Source="/AppName;component/Images/ImageName.jpg" Width="50" Height="50" />
</Grid>
Or:
<Grid>
<Image Source="/AppName;component/Images/ImageName.jpg"
Width="50" Height="50" Panel.ZIndex="1" />
<Border Background="Black" />
</Grid>
To find out how to data bind a BitmapImage to an Image.ItemsSource property, please see the Bind Xaml bitmap image question here on StackOverflow. To position the Image in a specific place, you can either use the Image.Margin property or put it in a Canvas and use the Canvas.Left and Canvas.Top properties.

Related

Is there any way to grab the frames from media element like a video without feeling any delay? - WPF

I have to show the frames from a media element in an Image control like a video. I have tried to grab continues frames from media element using a timer and bind that bitmap to Image source. But when setting the scale as 1, it seems like frames are grabbing very slowly. And when reduce the scale to 0.3 or below, the grabbing is working very fast. but the quality of frame is reducing.
Is there any way to solve this?
In short, I want to display the frames from media element to an Image source without any delay and with original quality.
<MediaElement x:Name="MediaEL" Volume="0" ScrubbingEnabled="True" SnapsToDevicePixels="True" MediaOpened="MediaEL_MediaOpened" LoadedBehavior="Manual" MediaEnded="MediaEL_MediaEnded" MediaFailed="MediaEL_MediaFailed">
</MediaElement>
<Image Name="ImageViewerMediaEL" />
ScreenShotimer = new DispatcherTimer();
ScreenShotimer.Interval = TimeSpan.FromMilliseconds(35);//35//
ScreenShotimer.Tick += ScreenShotimer_Tick;
public Bitmap TakeScreenshot(MediaElement medElement, double scale)
{
Bitmap screenBitmap = null;
double actualHeight = medElement.NaturalVideoHeight;
double actualWidth = medElement.NaturalVideoWidth;
double renderHeight = actualHeight * scale;
double renderWidth = actualWidth * scale;
if ((int)renderWidth > 0 && (int)renderHeight > 0)
{
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth,
(int)renderHeight, 96, 96, PixelFormats.Default);
VisualBrush sourceBrush = new VisualBrush(medElement);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0),
new System.Windows.Point(actualWidth, actualHeight)));
}
renderTarget.Render(drawingVisual);
MemoryStream stream = new MemoryStream();
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
encoder.Save(stream);
screenBitmap = new Bitmap(stream);
}
return screenBitmap;
}
Using a WinForms Bitmap in a WPF application doesn't seem to be necessary.
Reuse a single instance of a RenderTargetBitmap that is only created when necessary and assigned to the Source property of the Image element.
As well, reuse the DrawingVisual and draw a rectangle with a VisualBrush only when size changes.
private readonly DrawingVisual visual = new DrawingVisual();
private RenderTargetBitmap bitmap;
...
private void OnTimerTick(object sender, EventArgs e)
{
var width = MediaEL.NaturalVideoWidth;
var height = MediaEL.NaturalVideoHeight;
if (width > 0 && height > 0)
{
if (bitmap == null ||
bitmap.PixelWidth != width ||
bitmap.PixelHeight != height)
{
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(
new VisualBrush(MediaEL), null,
new Rect(0, 0, width, height));
}
bitmap = new RenderTargetBitmap(
width, height, 96, 96, PixelFormats.Default);
ImageViewerMediaEL.Source = bitmap;
}
bitmap.Render(visual);
}
}
The code above works fine for me with Microsoft's Wildlife.wmv and 35 ms timer interval.

How to calculate the intersection area on BitmapImage composition in WPF?

I am trying to merge two BitmapImage's into one composite image. But some parts are overlaping each other .
var green = new BitmapImage(new Uri(#"C:\temp\green.jpg", UriKind.RelativeOrAbsolute));
var red = new BitmapImage(new Uri(#"C:\temp\red.jpg", UriKind.RelativeOrAbsolute));
var visual = new DrawingVisual();
DrawingImage drawingImageSource;
using (DrawingContext drawingContext = visual.RenderOpen())
{
DrawingGroup imageDrawings = new DrawingGroup();
imageDrawings.Children.Add(new ImageDrawing(red, new Rect(0, 0, red.PixelWidth, red.PixelHeight)));
imageDrawings.Children.Add(new ImageDrawing(green, new Rect(red.PixelWidth - 10, red.PixelHeight - 10, green.PixelWidth, green.PixelHeight)));
drawingImageSource = new DrawingImage(imageDrawings);
RenderTargetBitmap bmp = new RenderTargetBitmap(red.PixelWidth + green.PixelWidth - offsetX, red.PixelHeight + green.PixelHeight - offsetY, 96, 96, PixelFormats.Pbgra32);
bmp.Render(visual);
//no binding, just my image control to keep it simple
this.fImage.Source = drawingImageSource;
}
XAML:
<Grid>
<Image x:Name="fImage"/>
</Grid>
I want to render the intersection area in different ways, e.g. mix the colors or gradient based transition. Are there some instruments in .NET or do I need to handle with pixels?

C# RenderTargetBitmap with grey borders

public RenderTargetBitmap GetSketchContentForExport()
{
Rect rectBounds = VisualTreeHelper.GetDescendantBounds(drawingCanvas);
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)rectBounds.Width, (int)rectBounds.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
VisualBrush visualBrush = new VisualBrush(drawingCanvas);
drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(), rectBounds.Size));
}
renderTarget.Render(drawingVisual);
return renderTarget;
}
When rendering the canvas content into a bitmap, all the content is displayed but has also grey borders (exactly the parts that are not in the current view).
Editing the resulting image in an external tool (XnView) and using the option "True Colour" fixes that problem. Does anyone see how I can fix this problem in my code? I appreciate any help!

How to use texture image .jpg as Windows.Media.pen C#

I have a texture image as .jpg and I want to use this image as Windows.Media.pen
I use Windows.Media.pen for drawing skeleton data in DrawingContext which I got it from microsoft kinect.
How can I use texture image .jpg as Windows.Media.pen?
solved the problem.
ImageSource image = new BitmapImage(new Uri(#"...\texture.jpg", UriKind.Relative));
var brush = new ImageBrush(image);
var pen = new Pen(brush, 10);
drawingContext.DrawLine(pen, XPos, YPos);
Welcome to StackOverflow :D
Not sure if you'd get what you've been expecting as you can see below but here's how to do it :
You need to use ImageBrush to be able to assign an image to a Pen.
Original image :
Result :
Code :
ImageSource image = new BitmapImage(new Uri(#"..\..\5c5f910416e2b92bb73fa59c56fe695d.png", UriKind.Relative));
var brush = new ImageBrush(image);
var pen = new Pen(brush, 50);
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(null, pen, new Rect(new Size(200, 200)));
}
var renderTargetBitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
Content = new Image {Source = renderTargetBitmap, Stretch = Stretch.None};

Resize bitmap image

I want to have smaller size at image saved.
How can I resize it?
I use this code for redering the image:
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height, 96d, 96d,
PixelFormats.Default);
renderBitmap.Render(surface);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
public static Bitmap ResizeImage(Bitmap imgToResize, Size size)
{
try
{
Bitmap b = new Bitmap(size.Width, size.Height);
using (Graphics g = Graphics.FromImage((Image)b))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, size.Width, size.Height);
}
return b;
}
catch
{
Console.WriteLine("Bitmap could not be resized");
return imgToResize;
}
}
The shortest way to resize a Bitmap is to pass it to a Bitmap-constructor together with the desired size (or width and height):
bitmap = new Bitmap(bitmap, width, height);
Does your "surface" visual have scaling capability? You can wrap it in a Viewbox if not, then render the Viewbox at the size you want.
When you call Measure and Arrange on the surface, you should provide the size you want the bitmap to be.
To use the Viewbox, change your code to something like the following:
Viewbox viewbox = new Viewbox();
Size desiredSize = new Size(surface.Width / 2, surface.Height / 2);
viewbox.Child = surface;
viewbox.Measure(desiredSize);
viewbox.Arrange(new Rect(desiredSize));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)desiredSize.Width,
(int)desiredSize.Height, 96d, 96d,
PixelFormats.Default);
renderBitmap.Render(viewbox);

Categories