How can I display real time view in wpf? - c#

I am trying to get real time view and my code is working in windows form but in wpf there is image instead of picturebox.Image. I get an error when I try to make equalization.
Here is the error code:
Can not implicitly convert type 'System.Drawing.Bitmap' to 'System.MediaControls.Image'
Here is the related part of the code:
if (btn_GetviewWasClicked)
{
Bitmap image = new Bitmap(width, height);
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bmpData = image.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr ptr = bmpData.Scan0;
Marshal.Copy(buf, 0, ptr, 1200000);
image.UnlockBits(bmpData);
img_original.Source = image;//Here is the part where the error exist
Bitmap image2 = new Bitmap(width, height);
Rectangle rect2 = new Rectangle(0, 0, width, height);
BitmapData bmpData2 = image2.LockBits(rect2, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr ptr2 = bmpData2.Scan0;
Marshal.Copy(bf, 0, ptr2, 1200000);
image2.UnlockBits(bmpData2);
img_original = image2;////Here is the part where the error exist
}

Using an extension function, like so
if (btn_GetviewWasClicked)
{
Bitmap image = new Bitmap(width, height);
img_original.Source = image.ToImageSource();
}
Where ToImageSource is an extension function
public static class WpfUtils {
public static BitmapImage ToImageSource(this Bitmap src)
{
var ms = new MemoryStream();
src.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
var image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
// Other Utility functions..
}

Related

Cropping a Base64/Bitmap, doesn't crop it

Currently I'm making a function which can take a base64 image and crop it to the desired rectangle (X, Y, Width, Height). However, the below code doesn't seem to do the trick and I don't know why. It returns the image unchanged and uncropped.
Can anyone see the issue? :)
public static string CropImage(string base64, int x, int y, int width, int height)
{
byte[] bytes = Convert.FromBase64String(base64);
using (var ms = new MemoryStream(bytes))
{
Bitmap bmp = new Bitmap(ms);
Rectangle rect = new Rectangle(x, y, width, height);
Bitmap croppedBitmap = new Bitmap(rect.Width, rect.Height, bmp.PixelFormat);
using (Graphics gfx = Graphics.FromImage(croppedBitmap))
{
gfx.DrawImage(bmp, 0, 0, rect, GraphicsUnit.Pixel);
}
using (MemoryStream ms2 = new MemoryStream())
{
bmp.Save(ms2, ImageFormat.Jpeg);
byte[] byteImage = ms2.ToArray();
var croppedBase64 = Convert.ToBase64String(byteImage);
return croppedBase64;
}
}
}
The cropped image is in croppedBitmap, bmp is the original image. I think you want to use croppedBitmap in the second memory stream:
using (MemoryStream ms2 = new MemoryStream())
{
croppedBitmap.Save(ms2, ImageFormat.Jpeg);
byte[] byteImage = ms2.ToArray();
var croppedBase64 = Convert.ToBase64String(byteImage);
return croppedBase64;
}

Large image update in WPF is delayed for real time monitoring

I am getting Sequence of images from USB and with each image grabbed I convert grabbed result to System.Drawing.Bitmap and after that I convert it to System.Windows.Mesia.Imging.BitmapImage to be able to assign it to Imagesource and finally update UI in dispatcher thread, all this process takes time and it doesn't go live, the sample codes of the camera company (Basler) has used C# and directly assigns System.Drawing.Bitmap to picture box and can show live view without delay.
What is the best solution to handle it ? it worth mentioning that with 2048*2000 pixel size the frame rate is almost 50 fps
PixelDataConverter converter = new PixelDataConverter();
Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr ptrBmp = bmpData.Scan0;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
bitmap.UnlockBits(bmpData);
BitmapImage bitmapimage = new BitmapImage();
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
}
Dispatcher.Invoke(new Action(() =>
{
imgMain.Source = bitmapimage;
}));
And this is the sample code for c# by company :
Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
// Lock the bits of the bitmap.
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
// Place the pointer to the buffer of the bitmap.
converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr ptrBmp = bmpData.Scan0;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult); //Exception handling TODO
bitmap.UnlockBits(bmpData);
// Assign a temporary variable to dispose the bitmap after assigning the new bitmap to the display control.
Bitmap bitmapOld = pictureBox.Image as Bitmap;
// Provide the display control with the new bitmap. This action automatically updates the display.
pictureBox.Image = bitmap;
if (bitmapOld != null)
{
// Dispose the bitmap.
bitmapOld.Dispose();
}
}
enter code here
Use Dispatcher.BeginInvoke instead of Dispatcher.Invoke(...to set the image asynchronous.
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
imgMain.Source = bitmapimage;
}));

Why doesn't this code always create an identical copy of a Bitmap?

public static class BitmapHelper {
public static Bitmap Clone(Bitmap bmp) {
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
Bitmap newbmp = new Bitmap(rect.Width, rect.Height);
using (Graphics gfx = Graphics.FromImage(newbmp)) {
gfx.InterpolationMode = InterpolationMode.High;
gfx.PixelOffsetMode = PixelOffsetMode.None;
gfx.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);
}
return newbmp;
}
}
Most of the time, this does create an identical copy, but if the original Bitmap passed to Clone was created by painting a section from a larger Bitmap where the section extended to the right-most edge of the larger Bitmap, then the copy I get back will have slightly altered pixels on its right-most edge.
What am I doing wrong?
The code that creates the original looks like this:
var SmallerImage = new Bitmap(_sqSize, _sqSize);
using (var gfx = Graphics.FromImage(SmallerImage)) {
gfx.InterpolationMode = InterpolationMode.High;
gfx.PixelOffsetMode = PixelOffsetMode.None;
gfx.DrawImage(LargerImage,
new Rectangle(0, 0, _sqSize, _sqSize),
new Rectangle(p.X, p.Y, _sqSize, _sqSize),
GraphicsUnit.Pixel);
}
The important thing to know there is that Point p and _sqSize are such that the source rectangle (the second rectangle in the DrawImage call) goes right up to the right-most edge of LargerImage.
This same code WILL create an identical copy when Point p and _sqSize are such that the source rectangle does not butt up to the right edge of LargerImage.
Can anyone tell me why this happens?
Or, can someone tell me how to RELIABLY create an EXACT pixel-for-pixel duplicate of a Bitmap? Seems like it ought to be easy, but I can't seem to do it.
new Bitmap(bmp) has the same problems as my Clone method. bmp.Clone() does seem to work, but it has problems under the covers (something about it not being a deep copy -- sharing data with the original) and using it breaks my code in many ways.
First, check that the image doesn't already have these artifacts before it is cloned.
Using Clone() is indeed only a shallow copy, but I believe that Clone(Rectangle, PixelFormat) is a deep clone:
public static Bitmap Clone(Bitmap bmp) {
var newbmp = bmp.Clone(new Rectangle(0, 0, bmp.Width, bmp.Height), bmp.PixelFormat);
return newbmp;
}
If that doesn't work, try copying the raw data:
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
public static Bitmap Clone(Bitmap bmp) {
var oldData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
var newBmp = new Bitmap(bmp.Width, bmp.Height, oldData.PixelFormat);
var newData = newBmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
CopyMemory(newData.Scan0, oldData.Scan0, (uint)(Math.Abs(oldData.Stride) * oldData.Height));
newBmp.UnlockBits(newData);
bmp.UnlockBits(oldData);
return newBmp;
}

C# convert stride/buffer/width/height to bitmap

I have an image width/height/stride and buffer.
How do I convert this information to a System.Drawing.Bitmap? Can I get the original image back if I have these 4 things?
There is a Bitmap constructor overload, which requires everything you have (plus PixelFormat):
public Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0);
This might work (if args.Buffer is an array of blittable type, like byte for example):
Bitmap bitmap;
var gch = System.Runtime.InteropServices.GCHandle.Alloc(args.Buffer, GCHandleType.Pinned);
try
{
bitmap = new Bitmap(
args.Width, args.Height, args.Stride,
System.Drawing.Imaging.PixelFormat.Format24bppRgb,
gch.AddrOfPinnedObject());
}
finally
{
gch.Free();
}
Update:
Probably it's better to copy image bytes to newly created Bitmap manually, because it seems like that constructors doesn't do that, and if byte[] array of image data gets garbage collected all sorts of bad things can happen.
var bitmap = new Bitmap(args.Width, args.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
var data = bitmap.LockBits(
new Rectangle(0, 0, args.Width, args.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
if(data.Stride == args.Stride)
{
Marshal.Copy(args.Buffer, 0, data.Scan0, args.Stride * args.Height);
}
else
{
int arrayOffset = 0;
int imageOffset = 0;
for(int y = 0; y < args.Height; ++y)
{
Marshal.Copy(args.Buffer, arrayOffset, (IntPtr)(((long)data.Scan0) + imageOffset), data.Stride);
arrayOffset += args.Stride;
imageOffset += data.Stride;
}
}
bitmap.UnlockBits(data);
This should work if you have the buffer as byte[], a width and the height + the pixelformat (stride)
public Bitmap CreateBitmapFromRawDataBuffer(int width, int height, PixelFormat imagePixelFormat, byte[] buffer)
{
Size imageSize = new Size(width, height);
Bitmap bitmap = new Bitmap(imageSize.Width, imageSize.Height, imagePixelFormat);
Rectangle wholeBitmap = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
// Lock all bitmap's pixels.
BitmapData bitmapData = bitmap.LockBits(wholeBitmap, ImageLockMode.WriteOnly, imagePixelFormat);
// Copy the buffer into bitmapData.
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bitmapData.Scan0, buffer.Length);
// Unlock all bitmap's pixels.
bitmap.UnlockBits(bitmapData);
return bitmap;
}

C# - Convert WPF Image.source to a System.Drawing.Bitmap

I've found loads of people converting a BitmapSource to a Bitmap, but what about ImageSource to Bitmap? I am making an imaging program and I need to extract bitmaps from the image displayed in the Image element. Does anyone know how to do this?
EDIT 1:
This is a function for converting the BitmapImage to a Bitmap. Remember to set the 'unsafe' option in the compiler preferences.
public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource srs)
{
System.Drawing.Bitmap btm = null;
int width = srs.PixelWidth;
int height = srs.PixelHeight;
int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);
byte[] bits = new byte[height * stride];
srs.CopyPixels(bits, stride, 0);
unsafe
{
fixed (byte* pB = bits)
{
IntPtr ptr = new IntPtr(pB);
btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr);
}
}
return btm;
}
Next is now to get a BitmapImage:
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
(int)inkCanvas1.ActualWidth,
(int)inkCanvas1.ActualHeight,
96d, 96d,
PixelFormats.Default);
targetBitmap.Render(inkCanvas1);
MemoryStream mse = new MemoryStream();
System.Windows.Media.Imaging.BmpBitmapEncoder mem = new BmpBitmapEncoder();
mem.Frames.Add(BitmapFrame.Create(targetBitmap));
mem.Save(mse);
mse.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = mse;
bi.EndInit();
Next is to convert it:
Bitmap b = new Bitmap(BitmapSourceToBitmap(bi));
Actually you don't need to use unsafe code. There's an overload of CopyPixels that accepts an IntPtr:
public static System.Drawing.Bitmap BitmapSourceToBitmap2(BitmapSource srs)
{
int width = srs.PixelWidth;
int height = srs.PixelHeight;
int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(height * stride);
srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride);
using (var btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr))
{
// Clone the bitmap so that we can dispose it and
// release the unmanaged memory at ptr
return new System.Drawing.Bitmap(btm);
}
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
That example worked for me:
public static Bitmap ConvertToBitmap(BitmapSource bitmapSource)
{
var width = bitmapSource.PixelWidth;
var height = bitmapSource.PixelHeight;
var stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
var memoryBlockPointer = Marshal.AllocHGlobal(height * stride);
bitmapSource.CopyPixels(new Int32Rect(0, 0, width, height), memoryBlockPointer, height * stride, stride);
var bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, memoryBlockPointer);
return bitmap;
}
Are your ImageSource not a BitmapSource? If your loading the images from files they should be.
Reply to your comment:
Sounds like they should be BitmapSource then, BitmapSource is a subtype of ImageSource. Cast the ImageSource to BitmapSource and follow one of those blogposts.
You don't need a BitmapSourceToBitmap method at all. Just do the following after creating your memory stream:
mem.Position = 0;
Bitmap b = new Bitmap(mem);

Categories