Повернуть математику изображения (С#)
У меня есть изображение с двумя точками, выровнено примерно так:
|----------------|
| |
| . |
| |
| . |
| |
|----------------|
У меня есть координаты X, Y для обеих точек, и мне нужно повернуть изображение X градусов, чтобы оно выглядело следующим образом:
|----------------|
| |
| |
| . . |
| |
| |
|----------------|
В принципе, они выравниваются рядом друг с другом, что математика для этого? (Пример кода на С# будет еще лучше, но не требуется)
Ответы
Ответ 1
Это зависит от того, какой пункт вы хотите использовать в качестве "центра" для вашего вращения. Позвольте называть точку в верхнюю и левую точку 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);
Надеюсь, что это поможет.
Ответ 2
Нет кода, извините, но стратагия.
Вам нужно создать образ результата, взяв образец исходного изображения. Вы знаете угол поворота, поэтому теперь вам нужно создать функцию 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)
Я думаю, будет отображаться исходный пиксель. Вам нужно будет проверить, не выходит ли это за рамки и просто черным или что-то еще:)
Ответ 3
Нижеприведенный код работает
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;
}
}
Ответ 4
Вам нужно искать геометрические матрицы вращения: Подробнее см. на этом сайте
Однако для достижения наилучших результатов вам необходимо преобразовать из адресата в источник, а затем использовать преобразование для каждого пикселя назначения:
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
. Вам нужно будет настроить перевод, чтобы переместить точку поворота изображения в начало координат, затем применить поворот, а затем другой перевод, чтобы вернуть его в исходное положение. Вам нужно будет поэкспериментировать с этими функциями, чтобы понять, как они себя ведут - я нахожусь на работе в данный момент, и у меня нет времени на то, чтобы сработать код, который работает.: - (
Ответ 5
Сначала найдите центральную точку:
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
.
См. Википедия для справки тригонометрических функций
Ответ 6
Выполнение общего двумерного преобразования включает в себя решение пары eqautions с 6 неизвестными.
'x = xA + yB + C
'y = xD + yE + D
Учитывая 3 соответствующие точки, у вас будет 6 известных и система может быть решена. В этом случае у вас всего 4 балла, так как вы не заботитесь о сдвиге, но вы можете представить себе 3-ю точку на 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, новое изменение константами A и D во внутреннем цикле.