Масштабирование изображения с помощью мыши в приложении WinForms? - PullRequest
3 голосов
/ 02 апреля 2010

Я пытаюсь использовать положение мыши для вычисления коэффициента масштабирования для масштабирования изображения.По сути, чем дальше вы удаляетесь от центра изображения, тем больше оно становится;и чем ближе к центру, тем меньше он становится.У меня пока есть какой-то код, но он действует очень странно, и у меня больше нет идей.Во-первых, я дам вам знать, что я пытался сделать средние 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++;

    }
}

РЕДАКТИРОВАТЬ: Благодаря Бену Фойгту и Рэю все теперь работает хорошо.Единственное, что неправильно, так это то, как я это делаю, изображение не сохраняет пропорции;но я исправлю это позже.Вот что я имею для тех, кто хочет знать:

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

        }
    }

Ответы [ 2 ]

1 голос
/ 02 апреля 2010

Масштабирование не будет плавным, если вы используете центр изображения. Вместо этого используйте начальную точку мыши (назовите ее p0). Кроме того, вместо того чтобы использовать расстояние от этой точки до текущей точки перетаскивания (e), просто возьмите разницу по одной оси (например, exp (e.Y - p0.Y)).

1 голос
/ 02 апреля 2010

Мне кажется (из расчета scaleAvg), что вы масштабируете уже масштабированное изображение. Это действительно плохая идея, потому что масштабирование с потерями и ошибки будут накапливаться. Вместо этого сохраните копию четкого оригинального изображения и масштабируйте оригинал непосредственно до текущего размера.

Кроме того, я бы предложил использовать другую норму, возможно, манхэттенское расстояние, вместо текущего декартового расстояния, которое является двумя нормами.

Если вы продолжаете использовать две нормы, рассмотрите возможность избавления от вызовов Math.Pow. Они, вероятно, настолько малы в общей сложности масштабирования, что это не имеет значения, но умножение само по себе должно быть намного быстрее, чем Math.Pow для возведения в квадрат числа.

...