I have code which I use to crop an image to a specified size. It does the job apart from the fact that, when I crop a bitonal image, it converts it to 24-bit colour which I don't want. Here's a snippet from the code ...
using (var Bmp = new Bitmap(FileImage.Width, Height))
{
using (var Graphic = Graphics.FromImage(Bmp))
{
var MemoryStreamTemp = new MemoryStream();
Graphic.DrawImage(FileImage, new Rectangle(0, 0, FileImage.Width, Height), x, CheckY, FileImage.Width, Height, GraphicsUnit.Pixel);
Bmp.Save(MemoryStreamTemp, ImageFormat.Tiff);
When bmp is created, it defaults to 24-bit colour. I realise that I can specify 1bpp indexed but that causes an exception when the Graphic object is instantiated.
I could convert the bitmap back to bitonal after it is cropped but that seems an unnecessary step that I would prefer to avoid.
Incidentally, I have a similar problem with the file's compression and resolution but that's for another day.
Related
This code basically takes an image and crops it according to a detected image (in this case, it detects a decentralized fingerprint, and returns a new Bitmap with the fingerprint centered and cropped).
It turns out that, depending on the image, each resulting Bitmap will have a different size (for example, my test is returning a 425x448 Bitmap, since the identified image has that size), when in fact I need the image to return with a specific size (512x512).
I've already tried to change all the height and width variables of the code, but none satisfy this desired condition. Either it creates a Bitmap with the size of 512x512 and stretches the original image (violating the original ratio), or it creates a 512x512 Bitmap with the cropped image but with a black border on the right and bottom sides.
Any hints of what can be changed or included in the code?
Edit: More clearly, I need to create a 512x512 canvas for the 425x448 image without changing the size or dimensions of the image (it should be 425x448 inside a 512x512 canvas).
private byte[] GetAndCropImage(byte[] image, IEnumerable<YoloItem> yoloItems)
{
byte[] imageRet = null;
var topYoloItem = yoloItems?.Where(x => x.Confidence >= 0.30).OrderByDescending(x => x.Confidence).First();
MemoryStream ms = new MemoryStream(image);
Bitmap src = new Bitmap(ms);
Rectangle cropRect = new Rectangle(topYoloItem.X, topYoloItem.Y, topYoloItem.Width, topYoloItem.Height);
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
}
target.SetResolution(512, 512);
ImageConverter converter = new ImageConverter();
imageRet = (byte[])converter.ConvertTo(target, typeof(byte[]));
return imageRet;
}
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 am getting the following Exception at ProcessImage(bitmap1, bitmap2);
Unsupported Pixel Format of source or template image
and this is my code:
public static double FindComparisonRatioBetweenImages(
System.Drawing.Image one, System.Drawing.Image two)
{
Bitmap bitmap1 = new Bitmap(one);
Bitmap bitmap2 = new Bitmap(two);
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0);
TemplateMatch[] matchings = null;
matchings = tm.ProcessImage(bitmap1, bitmap2); // Exception occurs here!
return matchings[0].Similarity;
}
I have also passed managedImage from the below code into the method, but it still gives error:
UnmanagedImage unmanagedImageA = UnmanagedImage.FromManagedImage(bitmap1);
Bitmap managedImageA = unmanagedImageA.ToManagedImage();
UnmanagedImage unmanagedImageB = UnmanagedImage.FromManagedImage(bitmap2);
Bitmap managedImageB = unmanagedImageB.ToManagedImage();
I have passed Images randomly from my computer, they all give exception.
I have passed Blank Image edited in paint into the method,it still give exception.
Also checked, jpeg, png, bmp formats, nothing work.
Try ExhaustiveTemplateMatching:
The class implements exhaustive template matching algorithm, which performs complete scan of source image, comparing each pixel with corresponding pixel of template.
The class processes only grayscale 8 bpp and color 24 bpp images.
So, those are the image formats you must use.
As requested, to convert to a specific pixel format, you can do this:
public static Bitmap ConvertToFormat(this Image image, PixelFormat format)
{
Bitmap copy = new Bitmap(image.Width, image.Height, format);
using (Graphics gr = Graphics.FromImage(copy))
{
gr.DrawImage(image, new Rectangle(0, 0, copy.Width, copy.Height));
}
return copy;
}
The one you would use is System.Drawing.Imaging.PixelFormat.Format24bppRgb.
After resizing an image, my resize function returns a newly drawn Image. I'm running into an issue where I need to determine what the file extension of the returned Image should be. I was using the Image.RawFormat property previously but everytime an Image is returned from this function it has ImageFormat.MemoryBMP, rather than ImageFormat.Jpeg or ImageFormat.Gif for example.
So basically my question is, how can I determine what file type the newly resized Image should be?
public static Image ResizeImage(Image imageToResize, int width, int height)
{
// Create a new empty image
Image resizedImage = new Bitmap(width, height);
// Create a new graphic from image
Graphics graphic = Graphics.FromImage(resizedImage);
// Set graphics modes
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Copy each property from old iamge to new image
foreach (var prop in imageToResize.PropertyItems)
{
resizedImage.SetPropertyItem(prop);
}
// Draw the new Image at the resized size
graphic.DrawImage(imageToResize, new Rectangle(0, 0, width, height));
// Return the new image
return resizedImage;
}
The resized image is not in any file based format, it is an uncompressed memory representation of the pixels in the image.
To save this image back to disk the data needs to be encoded in the selected format, which you have to specify. Look at the Save method, it takes an ImageFormat as a second argument, make that Jpeg or whatever format best fits your application.
In a windows forms application, I have as input a Drawing.Bitmap and a DrawingImage. I need to overlay them and put there output in a Controls.Image. How can I do this?
It doesn't matter if you use Image object or Bitmap object, The Drawing.Image is abstract class and Drawing.Bitmap inherited from it. to
draw image over image, get the graphics object from the base image and then use Graphics.DrawImage which accept parameter of type Image.
So you have two images here, one should be printed "overlay" over the other image:
System.Drawing.Image primaryImage = Image.FromFile(#"Your file path");//or resource..
using (Graphics graphics = Graphics.FromImage(primaryImage))//get the underlying graphics object from the image.
{
using (Bitmap overlayImage = new Bitmap(primaryImage.Width, primaryImage.Hieght,
System.Drawing.Imaging.PixelFormat.Format32bppArgb)//or your overlay image from file or resource...
{
graphics.DrawImage(overlayImage, new Point(0, 0));//this will draw the overlay image over the base image at (0, 0) coordination.
}
}
Control.Image = primaryImage;
Not that if the overlay image doesn't have some transparent, and its size is equals or larger than the base image, it will overlap the other image completely, so you the overlay image must have some opacity.
I realize it has been awhile, but the answers here weren't quite working for me. A little tweaking, though made them work fine. For what it is worth, here is my final version.
SCENARIO:
background image is RGB 24
overlay image is ARGB 32 with alpha channel already set properly.
images created from a memory stream
PROBLEM:
Creating the overlay image from the memory stream assumed I meant: Format32bppRgb
But what is needed is Format32bppArgb since the transparency is already in place..
SOLUTION:
pictureBox1.Image = MergeImages( backgroundImage, overlayImage);
using System.Drawing;
using System.Drawing.Imaging;
// ...
private Image MergeImages(Image backgroundImage,
Image overlayImage)
{
Image theResult = backgroundImage;
if (null != overlayImage)
{
Image theOverlay = overlayImage;
if (PixelFormat.Format32bppArgb != overlayImage.PixelFormat)
{
theOverlay = new Bitmap(overlayImage.Width,
overlayImage.Height,
PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(theOverlay))
{
graphics.DrawImage(overlayImage,
new Rectangle(0, 0, theOverlay.Width, theOverlay.Height),
new Rectangle(0, 0, overlayImage.Width, overlayImage.Height),
GraphicsUnit.Pixel);
}
((Bitmap)theOverlay).MakeTransparent();
}
using (Graphics graphics = Graphics.FromImage(theResult))
{
graphics.DrawImage(theOverlay,
new Rectangle(0, 0, theResult.Width, theResult.Height),
new Rectangle(0, 0, theOverlay.Width, theOverlay.Height),
GraphicsUnit.Pixel);
}
}
return theResult;
}