Image in PictureBox Become Blurry While Rotating - c#

I am trying to rotate an image that is in side of a PictureBox in a C# WinForm. I rotate the image with every tick of the timer1 (Interval = 100). As I am rotating, however, the image becomes blurrier and blurrier. I am not sure if there is a way to fix this. I have enabled the Form to be double buffered.
Here is the code I am using:
public static Image RotateImage(Image img, float rotationAngle)
{
Bitmap bmp = new Bitmap(img.Width, img.Height);
bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
Graphics gfx = Graphics.FromImage(bmp);
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
gfx.RotateTransform(-rotationAngle);
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
gfx.DrawImage(img, new Point(0, 0));
gfx.Dispose();
return bmp;
}
private void timer1_Tick(object sender, EventArgs e)
{
Image bmp = Form1.RotateImage(pictureBox1.Image, 10);
pictureBox1.Image = bmp;
}

Consider keeping your original image around, and each time you rotate, calculate the new image by applying the cumulative rotation to the original image.
What you're seeing is an unavoidable consequence of the rotation, which can only approximate the original image given the finite number of pixels it has to work with. You're seeing approximations of approximations, and they'll just get worse each time you rotate.

Related

Precision in rotating images

I searched a code to rotate an image in C#, and found this to be almost perfect. It does the job while keeping the same Height and Width properties of my old photo and maintaining its quality.
But, could you improve the code to make it more precise. For example when I send an angle of 0.0001 It doesn't seem to rotate it! (I really need to be so precise in this step)
public static Image RotateImage(Image img, float rotationAngle)
{
Bitmap bmp = new Bitmap(img.Width, img.Height);
turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
gfx.RotateTransform(rotationAngle);
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.DrawImage(img, new Point(0, 0));
gfx.Dispose();
return bmp;
}

image getting blurred when enlarging picture box

I am developing an application for image processing. To zoom the image, I enlarge PictureBox. But after enlarging I get below image as result.
But I want result like below image
Here is my Code :
picturebox1.Size = new Size((int)(height * zoomfactor), (int)
(width* zoomfactor));
this.picturebox1.Refresh();
The PictureBox by itself will always create a nice and smooth version.
To create the effect you want you need to draw zoomed versions yourself. In doing this you need to set the
Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
Then no blurring will happen..
Example:
private void trackBar1_Scroll(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pictureBox1.Image;
Size sz = bmp.Size;
Bitmap zoomed = (Bitmap)pictureBox2.Image;
if (zoomed != null) zoomed.Dispose();
float zoom = (float)(trackBar1.Value / 4f + 1);
zoomed = new Bitmap((int)(sz.Width * zoom), (int)(sz.Height * zoom));
using (Graphics g = Graphics.FromImage(zoomed))
{
if (cbx_interpol.Checked) g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.DrawImage(bmp, new Rectangle( Point.Empty, zoomed.Size) );
}
pictureBox2.Image = zoomed;
}
Of course you need to avoid setting the PBox to Sizemode Zoom or Stretch!

How to zoom picturebox along with graphics

I want to zoom picture box along with graphics.
this will Zoom the only image part not the graphics part.
public Image PictureBoxZoom(Image imgP, Size size)
{
Bitmap bm = new Bitmap(imgP, Convert.ToInt32(imgP.Width * size.Width), Convert.ToInt32(imgP.Height * size.Height));
Graphics grap = Graphics.FromImage(bm);
grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
return bm;
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if (zoomSlider.Value > 0 && img != null)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = null;
pictureBox1.Image = PictureBoxZoom(img, new Size(zoomSlider.Value, zoomSlider.Value));
}
}
the source of image is:
img = Image.FromStream(openFileDialog1.OpenFile());
Picture is zooming but when we draw the rectangle outside image then it's not zooming along with image.
See image:
You can do this (rather) easily by scaling the e.Graphics object in the Paint event.. See here for an example!
So to work with you code you probably should add this to the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(zoom, zoom);
// now do your drawing..
// here just a demo ellipse and a line..
Rectangle rect = panel1.ClientRectangle;
g.DrawEllipse(Pens.Firebrick, rect);
using (Pen pen = new Pen(Color.DarkBlue, 4f)) g.DrawLine(pen, 22, 22, 88, 88);
}
To calculate the zoom factor you need to do a little calculation.
Usually you would not create a zoomed Image but leave that job to the PictureBox with a SizeMode=Zoom.
Then you could write:
float zoom = 1f * pictureBox1.ClientSize.Width / pictureBox1.Image.Width;
To center the image one usually moves the PictureBox inside a Panel. And to allow scrolling one sets the Panel to Autocroll=true;
But since you are creating a zoomed Image you should keep track of the current zoom by some other means.
Note:
But as you use PictureBoxSizeMode.CenterImage maybe your problem is not with the zooming after all?? If your issue really is the placement, not the size of the drawn graphics you need to do a e.Graphics.TranslateTransform to move it to the right spot..

C# How to get pixel from stretched bitmap/picturebox

Okay, i have a pictureBox with an image, with a sizeMode set to: StretchImage,
Now, i want to get the pixel that i click. (bitmap.GetPixel(x,y)).
But when the image is streched from the normal size, i get the original pixel. as in the pixel that would be there before the strech(if that makes sense?)
My Code:
Private void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
Bitmap img = (Bitmap)pictureBox1.Image;
var color = img.GetPixel(e.X, e.Y)
}
Thanks In Advance
There should be a way to compensate for the stretching factor induced by the picture box. I'm thinking about taking the stretched width and height from the picture box, and the width and height from the original image, computing a stretching factor, and multiplying these with the e.X and e.Y coordinates.
Maybe something like:
Bitmap img = (Bitmap)pictureBox1.Image;
float stretch_X = img.Width / (float)pictureBox1.Width;
float stretch_Y = img.Height / (float)pictureBox1.Height;
var color = img.GetPixel((int)(e.X * stretch_X), (int)(e.Y * stretch_Y));
Divide the e.X and e.Y with stretching factor. Here is the stretched image fills the entire picture box.
Bitmap img = (Bitmap)pictureBox1.Image;
float factor_x = (float)pictureBox1.Width / img.Width;
float factor_y = (float)pictureBox1.Height / img.Height;
var color = img.GetPixel(e.X / factor_x, e.Y / factor_y)
By doing so, we make sure that e.X and e.Y will not exceed the limits of the original image.
You could store the original image and leave that untouched. It would be easier than resizing the stretched image and getting the specified pixel afterwords. Make sure that e.X and e.Y don't go outside the bounds of the original bitmap.
private Bitmap _img;
public void LoadImage(string file) {
// Get the image from the file.
pictureBox1.Image = Bitmap.FromFile(file);
// Convert it to a bitmap and store it for later use.
_img = (Bitmap)pictureBox1.Image;
// Code for stretching the picturebox here.
// ...
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
var color = _img.GetPixel(e.X, e.Y);
}
EDIT: Disregard. Maximilian's answer is better.

C# rotate bitmap 90 degrees

I'm trying to rotate a bitmap 90 degrees using the following function. The problem with it is that it cuts off part of the image when the height and width are not equal.
Notice the returnBitmap width = original.height and it's height = original.width
Can anyone help me solve this issue or point out what I'm doing wrong?
private Bitmap rotateImage90(Bitmap b)
{
Bitmap returnBitmap = new Bitmap(b.Height, b.Width);
Graphics g = Graphics.FromImage(returnBitmap);
g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
g.RotateTransform(90);
g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
g.DrawImage(b, new Point(0, 0));
return returnBitmap;
}
What about this:
private void RotateAndSaveImage(String input, String output)
{
//create an object that we can use to examine an image file
using (Image img = Image.FromFile(input))
{
//rotate the picture by 90 degrees and re-save the picture as a Jpeg
img.RotateFlip(RotateFlipType.Rotate90FlipNone);
img.Save(output, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
The bug is in your first call to TranslateTransform:
g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
This transform needs to be in the coordinate space of returnBitmap rather than b, so this should be:
g.TranslateTransform((float)b.Height / 2, (float)b.Width / 2);
or equivalently
g.TranslateTransform((float)returnBitmap.Width / 2, (float)returnBitmap.Height / 2);
Your second TranslateTransform is correct, because it will be applied before the rotation.
However you're probably better off with the simpler RotateFlip method, as Rubens Farias suggested.
I came across and with a little modification I got it to work. I found some other examples and noticed something missing that made the difference for me. I had to call SetResolution, if I didn't the image ended up the wrong size. I also noticed the Height and Width were backwards, although I think there would be some modification for a non square image anyway. I figured I would post this for anyone who comes across this like I did with the same problem.
Here is my code
private static void RotateAndSaveImage(string input, string output, int angle)
{
//Open the source image and create the bitmap for the rotatated image
using (Bitmap sourceImage = new Bitmap(input))
using (Bitmap rotateImage = new Bitmap(sourceImage.Width, sourceImage.Height))
{
//Set the resolution for the rotation image
rotateImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
//Create a graphics object
using (Graphics gdi = Graphics.FromImage(rotateImage))
{
//Rotate the image
gdi.TranslateTransform((float)sourceImage.Width / 2, (float)sourceImage.Height / 2);
gdi.RotateTransform(angle);
gdi.TranslateTransform(-(float)sourceImage.Width / 2, -(float)sourceImage.Height / 2);
gdi.DrawImage(sourceImage, new System.Drawing.Point(0, 0));
}
//Save to a file
rotateImage.Save(output);
}
}

Categories