Image Control not showing the webcam frames captured using OpenCVsharp - c#

I have Written the Code below in my XAML code behind to show webcame frames Received as Mat with Opencvsharp VideoCapture.Read() method in my Image Control named View.
Mat mat = new Mat();
VideoCapture videoCapture = new VideoCapture(2);
while (true)
{
videoCapture.Read(mat);
viewer.Source = mat.ToBitmapImage();
if (btn_stop.IsPressed)
{
break;
}
}
videoCapture.Release();
As u can see I used a converter to convert form Mat to BitmapImage so I can use it as image Source of my control. here are the Converters I used:
static class Converters
{
public static BitmapImage ToBitmapImage(this Bitmap bitmap)
{
BitmapImage bi = new BitmapImage();
MemoryStream ms = new MemoryStream();
bi.BeginInit();
bitmap.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
return bi;
}
public static BitmapImage ToBitmapImage(this Mat mat)
{
return BitmapConverter.ToBitmap(mat).ToBitmapImage();
}
}
Simply this code shows nothing in my image control and the app is freezed. I know that this code is generating too much garbage and I can't do anything about it. Any ideas about my problem? i Also changed my code with the instructions given in this link like below:
viewer.Source = (BitmapSource)new ImageSourceConverter().ConvertFrom(mat.ToBytes());
and also these converters:
public static BitmapImage ToBitmapImage(this Mat mat)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = new System.IO.MemoryStream(mat.ToBytes());
image.EndInit();
return image;
}
public static BitmapImage ToBitmapImage(this Mat mat)
{
using (var ms = new System.IO.MemoryStream(mat.ToBytes()))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
return image;
}
}
none of these worked for me.

heres the answer according to Clemens's comment:
Simply insantiate a DispatcherTimer object in MainWindow's constructor and use the Tick event to update the UI:
DispatcherTimer Timer = new DispatcherTimer();
Timer.Tick += Timer_Tick;
Timer.Interval = TimeSpan.FromMilliseconds(30);
Timer.Start();
private void Timer_Tick(object sender, EventArgs e)
{
if (videoCapture.Read(frame))
{
view.Source = OpenCvSharp.Extensions.BitmapSourceConverter.ToBitmapSource(frame);
}
}

Related

Record screen and save as video

I'm making a wpf application that will record the screen or take a screen shot. I figure out how to take a screen shot and also I show screen in the application. But I couldn't find how to create a video with them.
This is code that I'm screen shot the screen:
private BitmapImage CaptureScreen() {
System.Drawing.Rectangle screenSize = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
Trace.WriteLine(screenSize.Width);
Trace.WriteLine(screenSize.Height);
System.Drawing.Bitmap target = new System.Drawing.Bitmap(screenSize.Width, screenSize.Height);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(target)) {
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(screenSize.Width, screenSize.Height));
}
BitmapImage bitmapImage = new BitmapImage();
using (MemoryStream memory = new MemoryStream()) {
target.Save(memory, ImageFormat.Png);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
return bitmapImage;
}
This is code that how I'm record:
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(Events);
dispatcherTimer.Start();
private void Events(object sender, EventArgs e) {
// ScreenImage is an image that I'm using for see what app is recording
ScreenImage.Source = CaptureScreen();
}
Finnaly what I'm asking is :
I need to write a video file from image that I take from CaptureScreen()

Loading images into a Grid asynchronously

I'm developing a small application which will get RAW image files, convert them to low quality JPEG's then load those JPEG's as thumbnails into a Grid.
My problem: I am having issues with the UI getting blocked while the images are being converted. I am dynamically adding controls to host those images in the grid just after the conversion is taking place for each image. Also I am binding those images to my Image control's Source with my ControlProperties ViewModel in code-behind.
My coding:
Here I am creating a new instance of my ControlProperties view model and inside I am doing the image conversion at the ImageSource.
cp = new ControlProperties()
{
ImageId = controlCount += 1, ImageSource = ThumbnailCreator.CreateThumbnail(imagePath)
};
My question:
Seeing as the images take a while to load, I am in need to get full control of my UI while they are being converted and added into my grid, but I am not getting it right at all. Can someone please help me with some advice or coding snippets to get me going please?
My ThumbnailCreator class
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace SomeProjName
{
public class ThumbnailCreator
{
private static string imageLocation;
private static int currentImage;
public static BitmapImage CreateThumbnail(string oldImagePath)
{
ConvertHighQualityRAWImage(oldImagePath);
if (imageLocation != string.Empty && imageLocation != null)
return OpenImage(imageLocation);
else return null;
}
//Creates low quality JPG image from RAW image
private static void ConvertHighQualityRAWImage(string oldImagePath)
{
BitmapImage image = new BitmapImage(new Uri(oldImagePath));
var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
encoder.Frames.Add(BitmapFrame.Create(image));
using (var filestream = new FileStream(GetImageLocation(), FileMode.Create))
encoder.Save(filestream);
image.UriSource = null;
image.StreamSource = null;
image = null;
GC.WaitForPendingFinalizers();
GC.Collect();
}
//Returns low quality JPG thumbnail to calling method
private static BitmapImage OpenImage(string imagePath)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.DecodePixelWidth = 283;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(imagePath, UriKind.Relative);
image.EndInit();
DeleteImage();
return image;
}
private static string GetImageLocation()
{
imageLocation = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "thumbnails")).FullName + GetCurrentImage();
return imageLocation;
}
private static string GetCurrentImage()
{
return "\\" + (currentImage += 1).ToString() + ".jpg";
}
private static void DeleteImage()
{
if (File.Exists(imageLocation))
File.Delete(imageLocation);
}
}
}
You don't need to save your thumbnails to file. Use a MemoryStream instead:
public class ThumbnailCreator
{
public static BitmapImage CreateThumbnail(string imagePath)
{
BitmapFrame source;
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
source = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
encoder.Frames.Add(BitmapFrame.Create(source));
var bitmap = new BitmapImage();
using (var stream = new MemoryStream())
{
encoder.Save(stream);
stream.Position = 0;
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
return bitmap;
}
The intermediate encoding and decoding pass doesn't even seem to be necessary, so you could simply write this:
public class ThumbnailCreator
{
public static BitmapImage CreateThumbnail(string imagePath)
{
var bitmap = new BitmapImage();
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
return bitmap;
}
}
If you want to call the CreateThumbnail method asynchronously, use Task.Run():
cp.ImageSource = await Task.Run(() => ThumbnailCreator.CreateThumbnail(fileName));
Final Solution:
I just want to add this comment to Clemens solution. I also use the Garbage Collector to stop massive memory usage build-up when loading a lot of images. Here is the final method that I use to create the thumbnails.
public static BitmapImage CreateThumbnail(string imagePath)
{
var bitmap = new BitmapImage();
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
GC.WaitForPendingFinalizers();
GC.Collect();
return bitmap;
}

C# : Get Source of Image from Memory over Bitmap and BitmapImage

-I am trying to write a method for a Card Scanner and I am quite new in C# :)
-The application I wrote can scan and gets the images from the Scanner, but I can not show them on the WPF.
-The SDK is written for Windows Forms, so I have to do a conversion from Bitmap to BitmapImage (What I actually did).
-When I try to add a Source with XAML, it works, but it should get the Source from the Memory! But I have no Idea how it supposed to be on C#
Please help! I´ve tried almost everything. Thank you
class StartScan
{
protected internal SDKWrapper sdk = new SDKWrapper();
MainWindow mw;
public void Scan()
{
try
{
ShowImage(sdk.ScanAndGetImage(), false);
}
catch (Exception e)
{
System.Console.WriteLine(e.ToString());
}
}
private void ShowImage(System.Drawing.Image image, bool converted)
{
mw = new MainWindow();
if (image == null)
{
System.Console.WriteLine("IMAGE=NULL");
return;
}
int displayW =(int) mw.CardBoxRect.Width;
int displayH = (int) mw.CardBoxRect.Height;
Bitmap b = new Bitmap(displayW,displayH);
mw.CardBox.Source = BitmapToImageSource(b);
}
BitmapImage BitmapToImageSource(Bitmap bitmap)
{
using (MemoryStream memory = new MemoryStream())
{
System.Console.WriteLine(bitmap.ToString());
bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
return bitmapimage;
}
}
}

WPF BitmapImage - EndInit() throwing NotSupportedException

I have to convert BitmapImage (JPEG inside) to byte[] and then back.
Here is my code:
using System.IO;
using System.Windows.Media.Imaging;
public class CImageConverter
{
//
public BitmapImage ByteArray_To_BitmapImage(byte[] _binaryData)
{
BitmapImage _bitmapImage = new BitmapImage();
//
_bitmapImage.BeginInit();
_bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
_bitmapImage.StreamSource = new MemoryStream(_binaryData);
_bitmapImage.EndInit();
//
return _bitmapImage;
}
//
public byte[] BitmapImage_To_ByteArray(BitmapImage _bitmapImage)
{
byte[] bytes;
//
using(MemoryStream ms = new MemoryStream())
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(_bitmapImage));
encoder.Save(ms);
bytes = ms.ToArray();
}
//
return bytes;
}
}
It seems that BitmapImage_To_ByteArray working properly.
But ByteArray_To_BitmapImage throwing NotSupportedException in EndInit() method.
The message is (translated with web-translator):
Could not locate the image processing component which is suitable to
complete this operation.
I found similar questions on the internet, but the answers do not work. The usual answer is "I tried your code - I have everything working fine."
I also found this suggestion, but did not understood, how to use it.
Thanks for your help!
public BitmapImage ToImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad; // here
image.StreamSource = ms;
image.EndInit();
return image;
}
}
Have you tried this?

Converting BitmapImage to Bitmap and vice versa

I have BitmapImage in C#. I need to do operations on image. For example grayscaling, adding text on image, etc.
I have found function in stackoverflow for grayscaling which accepts Bitmap and returns Bitmap.
So I need to convert BitmapImage to Bitmap, do operation and convert back.
How can I do this? Is this best way?
There is no need to use foreign libraries.
Convert a BitmapImage to Bitmap:
private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
// BitmapImage bitmapImage = new BitmapImage(new Uri("../Images/test.png", UriKind.Relative));
using(MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
return new Bitmap(bitmap);
}
}
To convert the Bitmap back to a BitmapImage:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
private BitmapImage Bitmap2BitmapImage(Bitmap bitmap)
{
IntPtr hBitmap = bitmap.GetHbitmap();
BitmapImage retval;
try
{
retval = (BitmapImage)Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(hBitmap);
}
return retval;
}
Here's an extension method for converting a Bitmap to BitmapImage.
public static BitmapImage ToBitmapImage(this Bitmap bitmap)
{
using (var memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
If you just need to go from BitmapImage to Bitmap it's quite easy,
private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
return new Bitmap(bitmapImage.StreamSource);
}
using System.Windows.Interop;
...
private BitmapImage Bitmap2BitmapImage(Bitmap bitmap)
{
BitmapSource i = Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return (BitmapImage)i;
}
I've just been trying to use the above in my code and I believe that there is a problem with the Bitmap2BitmapImage function (and possibly the other one as well).
using (MemoryStream ms = new MemoryStream())
Does the above line result in the stream being disposed of? Which means that the returned BitmapImage loses its content.
As I'm a WPF newbie I'm not sure that this is the correct technical explanation, but the code didn't work in my application until I removed the using directive.
Here the async version.
public static Task<BitmapSource> ToBitmapSourceAsync(this Bitmap bitmap)
{
return Task.Run(() =>
{
using (System.IO.MemoryStream memory = new System.IO.MemoryStream())
{
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage as BitmapSource;
}
});
}
Thanks Guillermo Hernandez, I created a variation of your code that works. I added the namespaces in this code for reference.
System.Reflection.Assembly theAsm = Assembly.LoadFrom("My.dll");
// Get a stream to the embedded resource
System.IO.Stream stream = theAsm.GetManifestResourceStream(#"picture.png");
// Here is the most important part:
System.Windows.Media.Imaging.BitmapImage bmi = new BitmapImage();
bmi.BeginInit();
bmi.StreamSource = stream;
bmi.EndInit();
This converts from System.Drawing.Bitmap to BitmapImage:
MemoryStream ms = new MemoryStream();
YOURBITMAP.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();

Categories