Convert WriteableBitmap to VideoFrame - A generic error occurred in GDI+ - c#

So i try to use ONNX file for local object detection, work great in UWP and WPF with local saved image.
Now, the problem is, to use my detection algorithm with 3D live camera.
My detection algorithm expect a (Windows.Media.)VideoFrame, and my camera give me an (System.Windows.Media.Imaging.)WriteableBitmap.
So here what i have donne already :
Convert my WriteableBitmap to Bitmap :
private System.Drawing.Bitmap BitmapFromWriteableBitmap(System.Windows.Media.Imaging.WriteableBitmap writeBmp)
{
System.Drawing.Bitmap bmp;
using (MemoryStream outStream = new MemoryStream())
{
System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)writeBmp));
enc.Save(outStream);
bmp = new System.Drawing.Bitmap(outStream);
}
return bmp;
}
Now i want to tranform my Bitmap to SoftwareBitmap (for creating a VideoFrame with VideoFrame.CreateWithSoftwareBitmap)
Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
Stream strm;
private async Task<SoftwareBitmap> SoftWareBitmapFromBitmap(Bitmap bitmap)
{
SoftwareBitmap softwareBitmap2;
strm = stream.AsStream();
bitmap.Save(strm, ImageFormat.Png);
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
softwareBitmap2 = await decoder.GetSoftwareBitmapAsync();
return softwareBitmap2;
}
But in this last function i got an error in :
bitmap.Save(strm, ImageFormat.Bmp);
I got the "A generic error occurred in GDI+."
I have try to lock/unlock the bitmap, i have try different ImageFormat, if i change to 'ImageFormat.MemoryBmp' i got an "Value cannot be null".
Thank you.

I dont know how to quotes or thumb up answer and sorry for that.
That work great just with : outStream.AsRandomAccessStream()
Here the final function :
public async Task<System.Windows.Shapes.Rectangle> GetPositionDetection(WriteableBitmap wrtBitmap, double imageWidth, double imageHeight)
{
try
{
MemoryStream outStream = new MemoryStream();
System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)wrtBitmap));
enc.Save(outStream);
Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(outStream.AsRandomAccessStream());
SoftwareBitmap tmp2 = await decoder.GetSoftwareBitmapAsync();
VideoFrame inputImage = VideoFrame.CreateWithSoftwareBitmap(tmp2);
IList<PredictionModel> ResultsList = await objDetec.PredictImageAsync(inputImage);
if (ResultsList.Count == 0)
{
Console.WriteLine("Object not detected");
return null;
}
else
{
var itm = ResultsList.First(x => x.Probability == ResultsList.Max(y => y.Probability));
System.Windows.Shapes.Rectangle rct = new System.Windows.Shapes.Rectangle();
rct.Stroke = System.Windows.Media.Brushes.Red;// new SolidColorBrush(Windows.UI.Colors.Red);
rct.StrokeThickness = 2;
rct.Width = imageWidth * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Width) / 100);
rct.Height = imageHeight * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Height) / 100);
Console.WriteLine("Object returned : " + ResultsList.Count);
return rct;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
Thank you for your help.

Related

How can i clear the memory after converting BitmapImage to Byte

I have two functions: one to convert from image to byte and other to convert from byte to bitmapImage.
So, when I open the window with that images, I convert from byte to bitmapImage and it works great, but when I close and open it again it just keeps on memory and if I continue to do that time and time again it just throws an exception Out Of Memory exception
Image to byte->
private byte[] ConvertImageToBinary(Image img)
{
using (MemoryStream ss = new MemoryStream())
{
img.Save(ss, System.Drawing.Imaging.ImageFormat.Jpeg);
var s = ss.ToArray();
var jpegQuality = 50;
Image image;
using (var inputStream = new MemoryStream(s))
{
image = Image.FromStream(inputStream);
var jpegEncoder = System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders()
.First(c => c.FormatID == System.Drawing.Imaging.ImageFormat.Jpeg.Guid);
var encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, jpegQuality);
Byte[] outputBytes;
using (var outputStream = new MemoryStream())
{
image.Save(outputStream, jpegEncoder, encoderParameters);
return outputBytes = outputStream.ToArray();
}
}
}
}
Byte to bitmap ->
public BitmapImage ConvertBinaryToImage(byte[] array)
{
var image = new BitmapImage();
using (var ms = new MemoryStream(array))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad; // here
image.StreamSource = ms;
image.EndInit();
image.Freeze();
}
return image;
}
When I open the WindowDragAndDrop it loads all the images
But when I close it it still uses the same amount of memory
Image is indeed disposable (https://learn.microsoft.com/en-us/dotnet/api/system.drawing.image?view=netframework-4.8), so you also need:
using (var image = Image.FromStream(inputStream)){
}
Around everywhere you use Image objects.

UWP - scaled image is damaged

I have a problem to place an image with down-scale. Image is rasterized and I don't know find way to place it correctly.
Is it possible to place picture without losing quality ?
Code:
public async Task<BitmapImage> BitmapTransform(string filePath, uint width)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return null;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
double ration =
enc.BitmapTransform.ScaledWidth = width;
enc.BitmapTransform.ScaledHeight = (uint)(((double)decoder.PixelHeight / (double)decoder.PixelWidth) * (double)width);
// write out to the stream
try
{
await enc.FlushAsync();
}
catch (Exception ex)
{
string s = ex.ToString();
}
// render the stream to the screen
BitmapImage bImg = new BitmapImage();
bImg.SetSource(ras);
return bImg;
}
You can choose the way of resizing - Nearest Neighbor, Linear, Cubic, Fant - by BitmapTransform.InterporationMode property.
Have you tried it?
https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmaptransform.interpolationmode
double ration =
enc.BitmapTransform.ScaledWidth = width;
enc.BitmapTransform.ScaledHeight = (uint)(((double)decoder.PixelHeight / (double)decoder.PixelWidth) * (double)width);
enc.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Cubic; // <----- Set the Interporation mode here
But the quality of result is vary. It's depend on the original image.

convert gdcm_image to .NET bitmap fail

Hi am trying to get bitmap to display from DICOM file , but when try to create bitmap from the buffer I get Parameter is not valid for the Bitmap constructor call. I use the following code
gdcm.ImageReader reader = new gdcm.ImageReader();
reader.SetFileName(_dicomFilePath);
if (reader.Read())
{
var image = reader.GetImage();
if (image != null)
{
byte[] imageByteArray = new byte[image.GetBufferLength()];
if (image.GetBuffer(imageByteArray))
{
MemoryStream stream = new MemoryStream();
stream.Write(imageByteArray, 0, imageByteArray.Length);
stream.Seek(0, SeekOrigin.Begin);
Bitmap bmp = new Bitmap(stream);
CurrentFrameDataGDCM = Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight((int)image.GetRows(), (int)image.GetColumns()));
}
}
}

Error" Parameter is not valid " while converting Bytes into Image

I am converting bytes into an image but I get an error
Parameter is not valid
I am pasting my code. Kindly check the code and suggested that was I am doing right or wrong.
Image arr1 = byteArrayToImage(Bytess);
This is the function.
public static Image byteArrayToImage(byte[] byteArrayIn)
{
if (null == byteArrayIn || byteArrayIn.Length == 0)
return null;
MemoryStream ms = new MemoryStream(byteArrayIn);
try
{
Process currentProcess1 = Process.GetCurrentProcess();
Image returnImage = Image.FromStream(ms);
return returnImage;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I applied many techniques and solutions but it did not work for me
Your answer would be appreciated.
Thanks
try this
public Image byteArrayToImage(byte[] byteArrayIn)
{
System.Drawing.ImageConverter converter = new System.Drawing.ImageConverter();
Image img = (Image)converter.ConvertFrom(byteArrayIn);
return img;
}
After trying many things I found a way which has a little bit more control.
In this example you can specify the pixel format and copy the bytes to a Bitmap.
byte[] buffer = GetImageBytes();
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var bitmap_data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(buffer, 0, bitmap_data.Scan0, buffer.Length);
bitmap.UnlockBits(bitmap_data);
var result = bitmap as Image;
The problem is because, you are bringing it incorrectly from database. Try changing your code like this:
while (registry.Read())
{
byte[] image = (byte[])registry["Image"];
}
In my case I got the error since my base64 string had wrong encoding before calling Image.FromStream.
This worked for me in the end:
byte[] bytes = System.Convert.FromBase64String(base64ImageString);
using (MemoryStream ms = new MemoryStream(bytes))
{
var image = Image.FromStream(ms);
image.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
}
cmd.CommandText="SELECT * FROM `form_backimg` WHERE ACTIVE=1";
MySqlDataReader reader6= cmd.ExecuteReader();
if(reader6.Read())
{
code4 = (byte[])reader6["BACK_IMG"]; //BLOB FIELD NAME BACK_IMG
}
reader6.Close();
MemoryStream stream = new MemoryStream(code4); //code4 is a public byte[] defined on top
pictureBox3.Image = Image.FromStream(stream);
try this,
public Image byteArrayToImage(byte[] byteArrayIn)
{
Image returnImage = null;
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
returnImage = Image.FromStream(ms);
}
return returnImage;
}

How do I create a thumbnail from an image using C# Win Mobile 6.5/Compact framework?

I am trying to make/use a smaller image than the one taken with the camera to display in parts of my program (due to memory issues...)
Unfortunately I don't seem to be able to find ways to make a smaller image/thumbnail on the mobile device - the way it is possible in normal windows...
Is there a way to make a smaller image on Win Mobile 6.5/Compact Framework?
For example - these do not work on Win Mobile
What is the "best" way to create a thumbnail using ASP.NET?
This looks promising - but i want to just put the image on a PictureBox - and not sure how to use this to make it work.
This code should be work. I have also implemented this code. For that I have used OpenNETCF.Drawing.dll.
barray = GetImage(filepath);
if (barray != null)
{
ms.Write(barray, 0, barray.Length - 1);
imageBitmap = CreateThumbnail(ms, new Size(PreviewImageWidth, PreviewImageHeight));
bm = ImageUtils.IBitmapImageToBitmap(imageBitmap);
// m_CurrentImageID = Convert.ToInt32(lstPic.ToList()[index].Id);
PictureBox ib = ((PictureBox)this.imagePanel.Controls[(nIndex * 2) + 1]);
ib.Image = bm;
}
private byte[] GetImage(string FilePath)
{
byte[] barray;
if (File.Exists(FilePath))
{
FileInfo _fileInfo = new FileInfo(FilePath);
long _NumBytes = _fileInfo.Length;
FileStream _FStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
BinaryReader _BinaryReader = new BinaryReader(_FStream);
barray = _BinaryReader.ReadBytes(Convert.ToInt32(_NumBytes));
_FStream.Flush();
_FStream.Dispose();
return barray;
}
else
{
return null;
}
}
public IBitmapImage CreateThumbnail(Stream stream, Size size)
{
IBitmapImage imageBitmap;
ImageInfo ii;
IImage image;
ImagingFactory factory = new ImagingFactoryClass();
try
{
factory.CreateImageFromStream(new StreamOnFile(stream), out image);
image.GetImageInfo(out ii);
factory.CreateBitmapFromImage(image, (uint)size.Width, (uint)size.Height, ii.PixelFormat, InterpolationHint.InterpolationHintDefault, out imageBitmap);
return imageBitmap;
}
catch (Exception ex)
{
CreateLogFiles Err = new CreateLogFiles();
Err.ErrorLog(ex.Message);
return null;
}
finally
{
imageBitmap = null;
image = null;
factory = null;
}
}
This should work:
this.pictureBox1.Image = System.Drawing.Image.FromFile(#"\path to image").GetThumbnailImage(100, 100, null, IntPtr.Zero);
but the quality of thumbnail may not be as good. For quality thumbnail images you could refer to this post here

Categories