Read an image with OpenCV in C++ and display it in C# - c#

I have a Mat in C++ which is presents my image.
I did some operation on in with OpenCV and now want to send it to my C# project and use it as an ImageSource.
But when I want to call the converter in c#, to convert it to ImageSource, I face to this error on bitmapObj.Save :
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
my sample C++ source is:
Bitmap^ SomeClass::Test(System::String^ imgFileName)
{
auto fileName = msclr::interop::marshal_as<string>(imgFileName);
Mat img = imread(fileName);
auto bmp = gcnew Bitmap(img.cols, img.rows, img.step, Imaging::PixelFormat::Format24bppRgb, (IntPtr)img.data);
img.release();
return bmp;
}
and my sample c# code is:
private void ImageTester(object sender, RoutedEventArgs e)
{
var image = testClass.Test("test.png");
bg.Source = ConvertToBitmapImageFromBitmap(image);
}
public static BitmapImage ConvertToBitmapImageFromBitmap(Bitmap btm)
{
using(var ms = new MemoryStream())
{
btm.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
BitmapImage bImg = new BitmapImage();
bImg.BeginInit();
bImg.StreamSource = new MemoryStream(ms.ToArray());
bImg.EndInit();
return bImg;
}
}

Related

How to create a Image or Mat instance from a YUV_420_888 byte array in EmguCV?

The problem:
I receive a YUV_420_888 image from an android device as a byte buffer (simply concatenated the image plane buffers). I know the dimension of the image and I need to display it onto my GUI.
What I have so far:
At the moment I can use only the grayscale Y-plane with the following function:
private BitmapImage GetImageFromBuffer(byte[] imgBuffer)
{
Image<Gray, byte> emguImg = new Image<Gray, byte>(1280, 720);
emguImg.Bytes = imgBuffer;
var img = new BitmapImage();
using (MemoryStream ms = new MemoryStream(emguImg.ToJpegData()))
{
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnLoad;
img.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
img.StreamSource = ms;
img.EndInit();
}
return img;
}
I also have tested a similar code, using Image.ToBitmap() function and copying the intermediate Bitmap to the memory stream, which serves as source for the BitmapImage.
Anyway, I would like to create a BitmapImage of BitmapSource (or any type I can use to display on the GUI) from the incoming byte[].
As far as I could read up on it, I have to create a Mat instance from the byte array, convert it to RGB and then save it to a diplay-able format.
The following code seems to do the trick:
private BitmapImage GetImageFromBuffer(byte[] imgBuffer)
{
unsafe
{
fixed (byte* p = imgBuffer)
{
IntPtr ptr = (IntPtr)p;
Mat yuvMat = new Mat(1080, 1280, Emgu.CV.CvEnum.DepthType.Cv8U, 1, ptr, 1280);
Mat rgbMat = new Mat();
CvInvoke.CvtColor(yuvMat, rgbMat, Emgu.CV.CvEnum.ColorConversion.Yuv420Sp2Rgb);
var img = new BitmapImage();
using (MemoryStream ms = new MemoryStream())
{
img.BeginInit();
rgbMat.Bitmap.Save(ms, ImageFormat.Bmp);
img.CacheOption = BitmapCacheOption.OnLoad;
img.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
img.StreamSource = ms;
img.EndInit();
}
return img;
}
}
}
Maybe someone can confirm, if this is the way to go or comment suggestions for improvements.

Image Control not showing the webcam frames captured using OpenCVsharp

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);
}
}

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;
}
}
}

Converting Byte[] to Image type in C# for Windows Phone 7

I am having a problem converting a Byte array into an Image type for displaying in an application on Windows Phone 7.
The data is retrieved from a server, and when I upload and download the data it works fine, but I am struggling when converting it back into an Image format.
Can anyone shed some light on this issue for me?
This is my method for turning the Byte array into a BitmapImage,
public BitmapImage decodeImage(byte[] array)
{
MemoryStream ms = new MemoryStream(array, 0, array.Length);
// Convert byte[] to Image
ms.Write(array, 0, array.Length);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(ms);
return bitmapImage;
}
Then this is the code where I try to set the returned BitmapImage to the source for the Image box I am using in the XAML UI.
BitmapImage usrIMG = new BitmapImage();
usrIMG = getJson.decodeImage(userProfile.Photos[0].Image);
profileImage.Source = usrIMG;
I know the code looks mishmashed, and I am declaring things that I dont need to, i have been fiddling with it for ages and I am completely at a loss.
Many Thanks
the following code works fine for me in a quick test for your scenario of using the PhotoChooserTask, and store the selected image in a byte array. You also might want to review your code where you store and retrieve the byte array on your side, to make sure nothing gets lost there.
private byte[] imageBytes;
private void GetPhoto_Click(object sender, RoutedEventArgs e)
{
PhotoChooserTask photoTask = new PhotoChooserTask();
photoTask.Completed += new EventHandler<PhotoResult>(photoTask_Completed);
photoTask.Show();
}
void photoTask_Completed(object sender, PhotoResult e)
{
imageBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(imageBytes, 0, imageBytes.Length);
// save 'imageBytes' byte array to data base ...
}
private void ShowPhoto_Click(object sender, RoutedEventArgs e)
{
// load 'imageBytes' byte array to data base ...
BitmapImage bitmapImage = new BitmapImage();
MemoryStream ms = new MemoryStream(imageBytes);
bitmapImage.SetSource(ms);
myImageElement.Source = bitmapImage;
}
You'll need a WritableBitmap and to know the height and width of the image to be able to do this.
Then you can do something like this:
var result = new WriteableBitmap(width, height);
var ms = new MemoryStream();
ms.Write(myByteArray, myByteArray, myByteArray.Length);
result.SetSource(ms);
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(new MemoryStream(..Binary array Data..));
img1.Source = bitmapImage;
public BitmapImage ByteArraytoBitmap(Byte[] byteArray)
{
MemoryStream stream = new MemoryStream(byteArray);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
i used this code before and it's work 100% successfuly.

How to convert varBinary into image or video when retrieved from database in C#

I am using visual studio 2010, (desktop application) and using LINQ to SQL to save image/video or audio files to database in dataType VarBinary (MAX). This I can do... Problem is, I can't get them and display them in xaml because I can't get the converting part correct. Here is what I have so far (though its not working);
private void bt_Click (object sender, RoutedEventArgs e)
{
databaseDataContext context = new databaseDataContext();
var imageValue = from s in context.Images
where s.imageID == 2
select s.imageFile;
value = imageValue.Single().ToString();
//convert to string and taking down to next method to get converted in image
}
public string value { get; set; }
public object ImageSource //taking from http://stackoverflow.com/
{
get
{
BitmapImage image = new BitmapImage();
try
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.UriSource = new Uri(value, UriKind.Absolute);
image.EndInit();
Grid.Children.Add(image);
}
catch { return DependencyProperty.UnsetValue; } return image;
}
}
I not even sure if I am on the correct track? And I am assuming that video or audio is quite similar methods?
Since your image is stored in binary format in the database, you want to "stream" this into an image object by leveraging the MemoryStream object.
Looking at your code, your solution will look something like this:
BitmapImage bmpImage = new BitmapImage();
MemoryStream msImageStream = new MemoryStream();
msImageStream.Write(value, 0, value.Length);
bmpCardImage.BeginInit();
bmpCardImage.StreamSource = new MemoryStream(msImageStream.ToArray());
bmpCardImage.EndInit();
image.Source = bmpCardImage;
It's very easy, if you have a binary data and want to create an Image object, use this code:
public Image BinaryToImage(byte[] binaryData)
{
MemoryStream ms = new MemoryStream(binaryData);
Image img = Image.FromStream(ms);
return img;
}
If you already have the bytes, to verify that what you saved is correct you can save the bytes to a file and open it....
string tempFile = Path.GetTempFileName();
MemoryStream ms = new MemoryStream(bytes); //bytes that was read from the db
//Here I assume that you're reading a png image, you can put any extension you like is a file name
FileStream stream = new FileStream(tempFile + ".png", FileMode.Create);
ms.WriteTo(stream);
ms.Close();
stream.Close();
//And here we open the file with the default program
Process.Start(tempFile + ".png");
And later you can use the answer of Dillie-O and stream....
Dillie-O's code makes for a very nice extension method:
// from http://stackoverflow.com/questions/5623264/how-to-convert-varbinary-into-image-or-video-when-retrieved-from-database-in-c:
public static BitmapImage ToImage(this Binary b)
{
if (b == null)
return null;
var binary = b.ToArray();
var image = new BitmapImage();
var ms = new MemoryStream();
ms.Write(binary, 0, binary.Length);
image.BeginInit();
image.StreamSource = new MemoryStream(ms.ToArray());
image.EndInit();
return image;
}

Categories