I am successfully drawn images from their raw pixel data.(only 8 bit images).
here is the code for doing the same thing.
PixelFormat format = PixelFormat.Format8bppIndexed;
Bitmap bmp = new Bitmap(Img_Width, Img_Height, format);
Rectangle rect = new Rectangle(0, 0, Img_Width, Img_Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, format);
Marshal.Copy(rawPixel, 0, bmpData.Scan0, rawPixel.Length);
bmp.UnlockBits(bmpData);
Now as you all know PixelFormat.format16bppGrayscale is not supported by c# 2.0 GDI+.
I googled and got 3.0/3.5 framework support this.
So i installed both.
The class which is support is System.windows.media.PixelFormats.
PixelFormats.Gray16
Now my problem is how to create a bitmap and get a image for display by passing this parameter.
i got something BitmapSource class there but i am very new in C#3.0.
Please help me.
Try this:
private static Bitmap changePixelFormat(Bitmap input, PixelFormat format)
{
Bitmap retval=new Bitmap(input.Width, input.Height, format);
retval.SetResolution(input.HorizontalResolution, input.VerticalResolution);
Graphics g = Graphics.FromImage(retval);
g.DrawImage(input, 0, 0);
g.Dispose();
return retval;
}
Take a look at the Greyscale filters in AForge.net. You can find source here.
EDIT:
As a note on that source I linked, it is using an 'old' version of AForge.NET, but the concepts are the same.
Related
I am trying to convert a grayscale Bitmap (Format16bppGrayScale) to a color Bitmap (Format32bppArgb) like so:
Bitmap color = gray.Clone(new Rectangle(0, 0, gray.Width, gray.Height), PixelFormat.Format32bppArgb);
I keep getting a System.OutOfMemoryException. I have been researching and this error usually occurs when the rectangle provided to Clone is bigger than the actual image that you are trying to clone. This is not the case here since I am using the image dimensions to create the rectangle. Are there known issues with this type of conversions? Are there any other ways to achieve a copy in a different PixelFormat?
Thanks,
I read, people have problem like you. Try this way:
Change PixelFormat, while you try clone, system have problem.
Biggest reason is new definition of Bitmap.
Bitmap clone = new Bitmap(gray.Width, gray.Height, PixelFormat.Format32bppArgb);
using (Graphics gr = Graphics.FromImage(clone)) {
gr.DrawImage(color, new Rectangle(0, 0, clone.Width, clone.Height));
}
Or without DrawImage function:
using (Bitmap color = gray.Clone(new Rectangle(0, 0, gray.Width, gray.Height), PixelFormat.Format32bppArgb))
{
// color is now in the desired format.
}
I'm trying to take a writeablebitmap that constantly updates and render it into an Image however only the top of the image displays and the middle and bottom 2/3's are black. I think it might have something to do with PixelFormat as the writeablebitmap is bgr24 and the image is rgb24. This is what I'm currently doing.
int bufferSize = videoRenderer.VideoWidth * videoRenderer.VideoHeight;
byte[] frameBuffer = new byte[bufferSize];
Marshal.Copy(videoRenderer.Bitmap.BackBuffer, frameBuffer, 0, bufferSize);
using (Bitmap frame = new Bitmap(videoRenderer.VideoWidth, videoRenderer.VideoHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, videoRenderer.VideoWidth, videoRenderer.VideoHeight);
BitmapData bmpData = frame.LockBits(rect, ImageLockMode.ReadWrite, frame.PixelFormat);
Marshal.Copy(frameBuffer, 0, bmpData.Scan0, bufferSize);
frame.UnlockBits(bmpData);
IntPtr hBitmap = frame.GetHbitmap();
source = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
}
Does something look horribly wrong, or is it most likely the pixelformat. And if the pixelformat, how would one go through each pixel in c# to swap the blue's and red's?
It can't be just the pixel format in this case (it wouldn't cause 1/3 of the image to be rendered and the rest to be black). The difference between BGR24 and RGB24 is just a color swap.
In your case it's probably has to do with a difference in stride between the bitmap and the video source.
And as far as converting from BGR24 to RGB24 you could do it manually by locking the writable bitmap and looping over each pixel and swapping the components but that is not going to have good performance.
A much better approach would be to use the FormatConvertedBitmap class.
I used the below code to clone a bitmap image without locking the original file. But i am facing an issue that cloned image (.Gif) is not the same as the original image. Especially, the color of the cloned image is not proper.
Am I doing anything wrong? Is any better way to have Image in memory and original file deleted from hard disk?
Code:
private Bitmap CloneImage(Bitmap src)
{
if (src == null)
return src;
Bitmap bitmap = new Bitmap(src.Size.Width, src.Size.Height, src.PixelFormat);
System.Drawing.Rectangle bounds = new System.Drawing.Rectangle(0, 0, src.Width, src.Height);
System.Drawing.Imaging.BitmapData bmpData = src.LockBits(bounds, System.Drawing.Imaging.ImageLockMode.ReadWrite, src.PixelFormat);
System.Drawing.Imaging.BitmapData newBmpData = bitmap.LockBits(bounds, System.Drawing.Imaging.ImageLockMode.ReadWrite, src.PixelFormat);
IntPtr bPtr = bmpData.Scan0;
IntPtr nbPtr = newBmpData.Scan0;
int bytes = Math.Abs(bmpData.Stride) * src.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(bPtr, rgbValues, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, nbPtr, bytes);
bitmap.UnlockBits(newBmpData);
src.UnlockBits(bmpData);
return bitmap;
}
Original Image:
Cloned image:
This looks like a palette issue. The individual pixels are at the right location, so the memcpy code is probably right.
Either also copy the palette, or use a 24 or 32 bit pixel format and use Graphics.FromImage to blit the source image onto the target bitmap. Then you can save as PNG which is probably going to be a smaller file anyway.
It is easier (less code) to clone the image by saving it to a MemoryStream. Then you can load it from the MemoryStream and you will have your cloned Bitmap and you won't have to mess with pixel formats.
According to this SO answer, what you are doing here should be as hard as,
private Bitmap CloneImage(Bitmap src)
{
return new Bitmap(src);
}
I have a small piece of C# code that uses a Kinect to detect up to 4 glyphs and draws and polygon between them on a canvas, as seen here:
I've tried to follow along to this in order to implement 2D augmented reality and project an image within the created polygon. I've read in a source image and tried to apply the BackwardQuadrilateralTransformation to it but can't seem to display the transformed image. I am probably using the wrong method but I have tried to convert the image and paint it onto a canvas with no luck. I'm not sure if I'm just massively misunderstanding the method and maybe it isn't possible, any help would be greatly appreciated. I can supply more sample code if required.
private void GlyphBackQuad(List<IntPoint> quadpoints)
{
Bitmap srcImage = new Bitmap( // my sample image filepath );
UnmanagedImage sourceImage = UnmanagedImage.FromManagedImage(srcImage);
BackwardQuadrilateralTransformation filter = new BackwardQuadrilateralTransformation(sourceImage, quadpoints);
filter.Apply(sourceImage);
Bitmap bmp = sourceImage.ToManagedImage();
ImageBrush ib = new ImageBrush();
ib.ImageSource = ConvertDrawingImage2MediaImageSource(bmp);
PolyCanvas.Background = ib;
}
After a further play around with the code I think I have developed a partial solution, it still needs some work but hopefully this is more helpful for people to read/debug.
private void GlyphBackQuad(List<IntPoint> quadpoints, Bitmap bmp)
{
// Read in bitmap source image and clone it to the same format as destination
Bitmap srcImage = AForge.Imaging.Image.Clone(new Bitmap( // my sample filepath), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
System.Drawing.Imaging.BitmapData bitmapData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// Convert to unmanaged image
UnmanagedImage unmanagedImage = new UnmanagedImage( bitmapData );
// Filter
BackwardQuadrilateralTransformation filter = new BackwardQuadrilateralTransformation(srcImage, quadpoints);
filter.ApplyInPlace(unmanagedImage);
// Convert back to managed image and save
Bitmap managedImage = unmanagedImage.ToManagedImage();
managedImage.Save( // my save filepath, System.Drawing.Imaging.ImageFormat.Png);
}
I have been having a tough time creating a thumbnail that is not horrible quality. So far the best code i've come up with is:
Bitmap bmp = new Bitmap(width, height);
Graphics graphic = Graphics.FromImage(bmp);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(photo, 0, 0, width, height);
return imageToByteArray(bmp);
Which produces this gem:
If I resize the same image in Paint.NET i get this:
Which is WAY better. Everything I've found on line points me to some variation of the code I have above. I know Paint.NET was open source at one point. Does anyone know what magic they were doing to create such nice resize functionality and if that functionality can be reproduced in C#?
UPDATE:
The original image from this example was a jpg
GIFs
I recalled reading that .NET has issues with palette-based formats, like GIF, so I dug up a few articles.
This article describes how to quantize (pick an optimum palette) to improve quality: http://msdn.microsoft.com/en-us/library/aa479306.aspx, as does this (badly formatted) article.
In brief, I believe GDI+ picks a non-optimum palette when performing the resize.
PNGs
PNGs are palette-based, so they may be prone to the same issues as GIFs. I'm not sure if it matters that the palette can be much larger.
JPEG-friendly example
This code should work fine on JPEGs (but does not render GIFs smoothly). If you try it and it pixelates a JPEG, then there is probably something else going on.
private static byte[] GetScaledImage( byte[] inputBytes, int width, int height ) {
Image img = null;
using( MemoryStream ms = new MemoryStream() ) {
ms.Write( inputBytes, 0, inputBytes.Length );
img = Image.FromStream( ms );
}
using( MemoryStream ms = new MemoryStream() ) {
using( Image newImg = new Bitmap( width, height ) ) {
using( Graphics g = Graphics.FromImage( newImg ) ) {
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage( img, 0, 0, width, height );
newImg.Save( ms, img.RawFormat );
return ms.GetBuffer();
}
}
}
}
since Bitmap(int,int) is effectively Bitmap(int,int,PixelFormat.Format32bppArgb) I think the problem is in source image. Try to create another intermediate copy of the image of the same size as source image if using palette, then use that 32bppArgb image source for your resize function.