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;
}
Related
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.
I have an image that contains some letters. Each of the letters has been placed in a Rectangle object.
The rectangles are of different sizes, but i want to save each of them to a new image which has the same size. In this case 260x260.
Here is my approach:
foreach(Rectangle letter in letters)
{
Bitmap letterBitmap = img2.Clone(letter, img2.PixelFormat);
Image newImage = (Image) letterBitmap;
Bitmap newLetterBitmap = new Bitmap(newImage, new Size(260, 260));
}
The Problem is that the size of the rectangle gets changed, so it fits the new size of the Bitmap. I just want the new image to have a black background and be bigger than the original rectangle.
Try something like this:
Bitmap newLetterBitmap = new Bitmap(260, 260);
Graphics g = Graphics.FromImage(newLetterBitmap);
g.DrawImageUnscaled(newImage, 0, 0);
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;
}
I have a set of Microsoft ISF (Ink Serialized Format) images, which I am attempting to convert to PNGs to include in a web page. I have successfully used the C# package Microsoft.Ink to draw the ink to a Bitmap and save as PNG:
byte[] data; // data has the raw bytes of the ISF file
Ink ink = new Ink();
Renderer renderer = new Renderer();
Stream outStream; // a Stream to hold the PNG data
ink.Load(data);
using (Strokes strokes = ink.Strokes) {
// get bounds of ISF
rect = strokes.GetBoundingBox(BoundingBoxMode.PointsOnly);
// create bitmap matching bounds
bm = new Bitmap(rect.Width, rect.Height);
// draw the ISF onto the Bitmap
using (Graphics g = Graphics.FromImage(bm)) {
g.Clear(Color.Transparent);
renderer.Draw(g, strokes);
}
}
// save the Bitmap to PNG format
bm.Save(outStream, System.Drawing.Imaging.ImageFormat.Png);
... however, the image dimensions seem to be abnormally large. Changing the BoundingBoxMode enum passed in to the GetBoundingBox method does not appear to change anything, and I'm getting images that are 465px × 660px and contain only a handwritten letter 'a' taking up maybe 25px × 30px in actual space.
Any suggestions on how to get a more accurate bounding box?
The bounding box rectangle is in "Inkspace" coordinates - create throwaway bitmap and graphics objects, then convert the rectangle using renderer.InkSpacetoPixel.
Add these lines between the GetBoundingBox call and the creation of the Bitmap bm, and the Bitmap should be sized correctly:
Bitmap bmTrash = new Bitmap(10, 10);
Graphics gTrash = Graphics.FromImage(bmTrash);
renderer.InkSpaceToPixel(gTrash, rect.Location);
renderer.InkSpaceToPixel(gTrash, rect.Size);