Reputation: 570
I'm trying to use the position of the mouse to calculate the scaling factor for scaling an image. Basically, the further you get away from the center of the image, the bigger it gets; and the closer to the center you get, the smaller it gets. I have some code so far but it's acting really strange and I have absolutely no more ideas. First I'll let you know, one thing I was trying to do is average out 5 distances to get a more smooth resize animation. Here's my code:
private void pictureBoxScale_MouseMove(object sender, MouseEventArgs e)
{
if (rotateScaleMode && isDraggingToScale)
{
// For Scaling
int sourceWidth = pictureBox1.Image.Width;
int sourceHeight = pictureBox1.Image.Height;
float dCurrCent = 0; // distance between the current mouse pos and the center of the image
float dPrevCent = 0; // distance between the previous mouse pos and the center of the image
System.Drawing.Point imgCenter = new System.Drawing.Point();
imgCenter.X = pictureBox1.Location.X + (sourceWidth / 2);
imgCenter.Y = pictureBox1.Location.Y + (sourceHeight / 2);
// Calculating the distance between the current mouse location and the center of the image
dCurrCent = (float)Math.Sqrt(Math.Pow(e.X - imgCenter.X, 2) + Math.Pow(e.Y - imgCenter.Y, 2));
// Calculating the distance between the previous mouse location and the center of the image
dPrevCent = (float)Math.Sqrt(Math.Pow(prevMouseLoc.X - imgCenter.X, 2) + Math.Pow(prevMouseLoc.Y - imgCenter.Y, 2));
if (smoothScaleCount < 5)
{
dCurrCentSmooth[smoothScaleCount] = dCurrCent;
dPrevCentSmooth[smoothScaleCount] = dPrevCent;
}
if (smoothScaleCount == 4)
{
float currCentSum = 0;
float prevCentSum = 0;
for (int i = 0; i < 4; i++)
{
currCentSum += dCurrCentSmooth[i];
}
for (int i = 0; i < 4; i++)
{
prevCentSum += dPrevCentSmooth[i];
}
float scaleAvg = (currCentSum / 5) / (prevCentSum / 5);
int destWidth = (int)(sourceWidth * scaleAvg);
int destHeight = (int)(sourceHeight * scaleAvg);
// If statement is for limiting the size of the image
if (destWidth > (currentRotatedImage.Width / 2) && destWidth < (currentRotatedImage.Width * 3) && destHeight > (currentRotatedImage.Height / 2) && destWidth < (currentRotatedImage.Width * 3))
{
AForge.Imaging.Filters.ResizeBilinear resizeFilter = new AForge.Imaging.Filters.ResizeBilinear(destWidth, destHeight);
pictureBox1.Image = resizeFilter.Apply((Bitmap)currentRotatedImage);
pictureBox1.Size = pictureBox1.Image.Size;
pictureBox1.Refresh();
}
smoothScaleCount = -1;
}
prevMouseLoc = e.Location;
currentScaledImage = pictureBox1.Image;
smoothScaleCount++;
}
}
EDIT: Thanks to Ben Voigt and Ray everything works well now. The only thing wrong is that with the way I'm doing it the image doesn't keep it's ratio; but I'll fix that later. Here's what I have for those who want to know:
private void pictureBoxScale_MouseMove(object sender, MouseEventArgs e)
{
if (rotateScaleMode && isDraggingToScale)
{
// For Scaling
int sourceWidth = pictureBox1.Image.Width;
int sourceHeight = pictureBox1.Image.Height;
int scale = e.X + p0.X; //p0 is the location of the mouse when the button first came down
int destWidth = (int)(sourceWidth + (scale/10)); //I divide it by 10 to make it slower
int destHeight = (int)(sourceHeight + (scale/10));
if (destWidth > 20 && destWidth < 1000 && destHeight > 20 && destWidth < 1000)
{
AForge.Imaging.Filters.ResizeBilinear resizeFilter = new AForge.Imaging.Filters.ResizeBilinear(destWidth, destHeight);
pictureBox1.Image = resizeFilter.Apply((Bitmap)currentRotatedImage);
pictureBox1.Size = pictureBox1.Image.Size;
pictureBox1.Refresh();
}
currentScaledImage = pictureBox1.Image; // This is only so I can rotate the scaled image in another part of my program
}
}
Upvotes: 3
Views: 1604
Reputation: 3109
You're scaling won't be smooth if you use the center of the image. Instead, use the initial mouse down point (call it p0). Also, rather than using the distance from that point to the current drag point (e), just take the difference along one axis (e.g. exp(e.Y - p0.Y)).
Upvotes: 1
Reputation: 283614
It looks to me (from the scaleAvg calculation) like you're rescaling the already-scaled image. This is a really bad idea because scaling is lossy and the errors will accumulate. Instead, keep a copy of the crisp original image and scale the original directly to the current size.
Also, I would suggest using a different norm, perhaps Manhattan distance, instead of the current Cartesian distance which is a two-norm.
If you do continue using the two-norm, consider getting rid of the Math.Pow calls. They are probably such a small part of the overall scaling complexity that it doesn't matter, but multiplying by itself should be much faster than Math.Pow for squaring a number.
Upvotes: 1