Поворот изображения по математике (C #) - PullRequest
10 голосов
/ 23 января 2009

У меня есть изображение с двумя точками, выровненное примерно так:

|----------------|
|                |
|    .           |
|                |
|          .     |
|                |
|----------------|

У меня есть обе координаты X, Y для обеих точек, и мне нужно повернуть изображение на X градусов, чтобы оно выглядело следующим образом:

|----------------|
|                |
|                |
|    .     .     |
|                |
|                |
|----------------|

В основном, поэтому они выровнены рядом друг с другом, что за математика для этого? (Пример кода на C # будет еще лучше, но не обязателен)

Ответы [ 6 ]

14 голосов
/ 23 января 2009

Это зависит от того, какую точку вы хотите использовать в качестве «центра» для вашего вращения. Давайте назовем точку в верхнюю и левую точки A, а другую - в правую и нижнюю точки B. Если вы хотите повернуть вокруг точки A так, чтобы точка B совпала с ней, вычисление угла поворота в радианах будет выглядеть так:

double angle = Math.Atan2(pointB.Y - pointA.Y, pointB.X - pointA.X);

Я не понимаю, как вы обрабатываете свое изображение, поэтому следующее применимо, только если вы используете System.Drawing.Graphics:

myImage.TranslateTransform(-pointA.X, -pointA.Y);
myImage.RotateTransform((float) angle, MatrixOrder.Append);
myImage.TranslateTransform(pointA.X, pointA.Y, MatrixOrder.Append);

Надеюсь, это поможет.

5 голосов
/ 23 января 2009

Нет кода, извините, но стратегия.

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

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

for (int plotY = 0; plotY < resultHeight; plotY++)
{
   for (int plotX = 0; plotX < resultWidth; plotX++)
   {
         resultImage.PlotPixel(getOriginalPixel(plotX, plotY, angleOfRotation));
   } 
}

Так что теперь нам просто нужен магический метод "getOriginalPixel", и вот тут-то и приходит математика.

Если мы повернем изображение на 0 градусов, тогда plotX, plotY - это просто X / Y исходного изображения. Но это не весело.

pickX = x * cos(angle) - y * sin(angle)
pickY = y * cos(angle) + x * sin(angle)

Я думаю, что будет соответствовать исходному пикселю. Вам нужно будет проверить, не вышло ли оно за пределы, и просто вернуть черный или что-то в этом роде:)

4 голосов
/ 16 февраля 2011

Код ниже работает

  Matrix mRotate = new Matrix();
    mRotate.Translate(Convert.ToInt32(Width.Value) / -2, Convert.ToInt32(Height.Value) / -2, MatrixOrder.Append);
    mRotate.RotateAt(theta, new Point(0, 0), MatrixOrder.Append);

    using (GraphicsPath gp = new GraphicsPath())
    {  // transform image points by rotation matrix
        gp.AddPolygon(new Point[] { new Point(0, 0), new Point(Convert.ToInt32(Width.Value), 0), new Point(0, Convert.ToInt32(Height.Value)) });
        gp.Transform(mRotate);
        PointF[] pts = gp.PathPoints;

        // create destination bitmap sized to contain rotated source image
        Rectangle bbox = boundingBox(bmpSrc, mRotate);
        Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height);


        using (Graphics gDest = Graphics.FromImage(bmpDest))
        {  // draw source into dest


            Matrix mDest = new Matrix();
            mDest.Translate(bmpDest.Width / 2, bmpDest.Height / 2, MatrixOrder.Append);
            gDest.Transform = mDest;
            gDest.DrawImage(bmpSrc, pts);
            gDest.DrawRectangle(Pens.Transparent, bbox);
            //drawAxes(gDest, Color.Red, 0, 0, 1, 100, "");
            return bmpDest;
        }
    }
2 голосов
/ 23 января 2009

Выполнение общего 2D-преобразования включает в себя решение пары уравнений с 6 неизвестными.

'x = xA + yB + C

'y = xD + yE + D

С учетом 3 соответствующих очков у вас будет 6 известных, и система может быть решена. В этом случае у вас есть только 4 точки, так как вас не волнует сдвиг, но вы могли бы представить, что вы вводите третью точку под углом 90 градусов к линии, образованной двумя другими точками. Создание повернутого изображения тогда (псевдо кодировано) выглядит примерно так:

for ( y = 0; y < height; y++ )
 for ( x = 0; x < width; x++ )
  {
    newx = x*A + y*B + C;
    newy = x*D + y*D + E;
    newimage(x,y ) = oldimage( newx, newy );
  }
}

Если важна производительность, умножения во внутреннем цикле можно оптимизировать, отметив, что y * B изменяется только во внешнем виде и что newx, newy изменяются на константы A и D во внутреннем цикле.

2 голосов
/ 23 января 2009

Сначала найдите центральную точку:

Point p = new Point((x1-x2)/2, (y1-y2)/2)

Затем используйте тригономентрию, чтобы определить угол. Я предполагаю, что мы переместили начало координат в нашу центральную точку, поэтому теперь у меня есть новые x3 и y3 для одной из точек.

hypotenuse = SqrRt(x3^2 + y3^2)

Решаем за неизвестный угол TH

Sin(TH) = opposite / hypotenuse

Итак, чтобы решить для TH нам нужно:

TH = Asin(y3 / hypotenuse)

Поворот на TH.

См. Справочник по тригонометрическим функциям в Википедии

2 голосов
/ 23 января 2009

Вам необходимо найти геометрические матрицы вращения: Подробное объяснение см. На этом сайте

Однако для достижения наилучших результатов вам необходимо выполнить преобразование из пункта назначения в источник, а затем использовать преобразование для каждого пикселя назначения:

m = rotation matrix

for each point p in destination
  p' = p.m
  get pixel p' from source
  set pixle p in destination

Есть, в .net Framework методы для всего этого: System.Drawing.Graphics.RotateTransform и System.Drawing.Graphics.TranslateTransform. Вам нужно будет настроить перевод, чтобы переместить точку поворота изображения в начало координат, затем применить вращение, а затем другой перевод, чтобы вернуть его в исходное положение. Вам нужно будет поэкспериментировать с этими функциями, чтобы понять, как они себя ведут. Сейчас я нахожусь на работе, и у меня нет времени, чтобы собрать вместе работающий код. : - (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...