在 WinForms 应用程序中使用鼠标缩放图像?

发布于 2024-08-27 07:05:41 字数 4122 浏览 2 评论 0原文

我正在尝试使用鼠标的位置来计算缩放图像的缩放因子。基本上,距离图像中心越远,它就越大;越靠近中心,它就越小。到目前为止我有一些代码,但它的表现真的很奇怪,我绝对没有更多的想法。首先我会让你知道,我试图做的一件事是平均 5 个距离以获得更平滑的调整大小动画。这是我的代码:

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++;

    }
}

编辑:感谢 Ben Voigt 和 Ray 现在一切正常。唯一的问题是,按照我的方式,图像不能保持其比例;但我稍后会解决这个问题。这是我为那些想知道的人准备的:

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

        }
    }

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

        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

反目相谮 2024-09-03 07:05:41

如果使用图像的中心,缩放将不会平滑。相反,请使用初始鼠标按下点(称为 p0)。另外,不要使用从该点到当前拖动点 (e) 的距离,而只需沿一个轴求差值(例如 exp(eY - p0.Y))。

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)).

夜夜流光相皎洁 2024-09-03 07:05:41

在我看来(从scaleAvg计算)就像你正在重新缩放已经缩放的图像。这是一个非常糟糕的主意,因为缩放是有损的并且错误会累积。相反,保留清晰原始图像的副本并将原始图像直接缩放到当前尺寸。

另外,我建议使用不同的范数,也许是曼哈顿距离,而不是当前的笛卡尔距离,这是一个二范数。

如果您继续使用二范数,请考虑删除 Math.Pow 调用。它们可能只占整体缩放复杂性的一小部分,因此并不重要,但乘以自身应该比 Math.Pow 对数字进行平方要快得多。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文