Поворот изображения math (C#)
у меня есть изображение с двумя точками, выровненными примерно так:
|----------------|
| |
| . |
| |
| . |
| |
|----------------|
у меня есть координаты X, Y для обеих точек, и мне нужно повернуть изображение на x градусов, чтобы оно выглядело так:
|----------------|
| |
| |
| . . |
| |
| |
|----------------|
в основном, чтобы они выровнялись рядом друг с другом, какова математика для этого? (Пример кода на C# был бы еще лучше, но не требуется)
6 ответов
это зависит от того, какую точку вы хотите использовать в качестве "центра" для вашего вращения. Давайте назовем точку вверх и влево pointA и один справа и ниже pointB. Если вы хотите повернуть вокруг точки A так, чтобы точка B совпадала с ней, вычисление угла поворота в радианах будет выглядеть так:
double angle = Math.Atan2(pointB.Y - pointA.Y, pointB.X - pointA.X);
Я не знаю, как вы обрабатываете свой образ, поэтому следующее применимо только в том случае, если вы используете систему.Рисунок.Графика:
myImage.TranslateTransform(-pointA.X, -pointA.Y);
myImage.RotateTransform((float) angle, MatrixOrder.Append);
myImage.TranslateTransform(pointA.X, pointA.Y, MatrixOrder.Append);
надеюсь, что это помогает.
нет кода, извините, но хитрость.
вы должны иметь возможность создавать результирующее изображение путем выборки исходного изображения. Вы знаете угол поворота, поэтому теперь вам нужно создать функцию mapper, которая отображает результат обратно в оригинал.
код будет просто сканировать каждую строку результирующего изображения и сопоставлять пиксель с исходным изображением. Вы можете сделать простой;
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)
Я думаю, будет отображаться на исходный пиксель. Вам нужно будет проверить, если это за пределами и просто вернуть черный или что-то :)
ниже код работает
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;
}
}
сначала найдите центральную точку:
Point p = new Point((x1-x2)/2, (y1-y2)/2)
затем используйте trigonomentry для решения угла. Я собираюсь предположить, что мы переназначили начало координат в нашу центральную точку, поэтому теперь у меня есть новые x3 и y3 в одну из точек.
hypotenuse = SqrRt(x3^2 + y3^2)
мы решаем для неизвестного угла TH
Sin(TH) = opposite / hypotenuse
Итак, чтобы решить для че нам нужно:
TH = Asin(y3 / hypotenuse)
поворот на TH
.
выполняя обычный 2D преобразование предполагает решение пары eqautions с 6 неизвестными.
' x = xA + yB + c
' y = xD + yE + D
учитывая 3 соответствующие точки, у вас будет 6 knowns, и система может быть решена. В этом случае у вас есть только 4 точки, так как вы не заботитесь о сдвиге, но вы можете представить себе введение 3-й точки под углом 90 к линии, образованной двумя другими точками. Создание повернутого изображения затем (псевдо codedily ) просто что-то вроде:
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 во внутреннем цикле.
вам нужно посмотреть геометрические матрицы вращения:см. этот сайт для подробного объяснения
однако для достижения наилучших результатов вам нужно преобразовать из назначения в источник, а затем использовать преобразование для каждого пикселя назначения:
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
. Вам нужно будет настроить перевод, чтобы переместить точку вращения изображения в начало координат, а затем применить поворот, а затем еще один перевод, чтобы вернуть его в исходное положение. Вам нужно будет поэкспериментировать с этими функциями, чтобы понять, как они себя ведут - я сейчас на работе, и у меня нет времени, чтобы собрать какой-то код, который работает. :-(