Для этого есть некоторые алгоритмы looooong и hungry, но пока я не придумал и не нашел что-то особенно быстрое.Каков самый быстрый способ поворота изображения без обрезки его ребер с помощью GDI +?
ответ
Вот что я в конечном итоге делает (после обширного количества дальнейших исследований, а также полезная ссылка предоставлена TheCodeKing):
public Image RotateImage(Image img, float rotationAngle)
{
// When drawing the returned image to a form, modify your points by
// (-(img.Width/2) - 1, -(img.Height/2) - 1) to draw for actual co-ordinates.
//create an empty Bitmap image
Bitmap bmp = new Bitmap((img.Width * 2), (img.Height *2));
//turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
//set the point system origin to the center of our image
gfx.TranslateTransform((float)bmp.Width/2, (float)bmp.Height/2);
//now rotate the image
gfx.RotateTransform(rotationAngle);
//move the point system origin back to 0,0
gfx.TranslateTransform(-(float)bmp.Width/2, -(float)bmp.Height/2);
//set the InterpolationMode to HighQualityBicubic so to ensure a high
//quality image once it is transformed to the specified size
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//draw our new image onto the graphics object with its center on the center of rotation
gfx.DrawImage(img, new PointF((img.Width/2), (img.Height/2)));
//dispose of our Graphics object
gfx.Dispose();
//return the image
return bmp;
}
Ура!
void Graphics.RotateTransform(float angle);
Это должно повернуть изображение на C#. Что он делает вместо этого?
Я не слишком много экспериментировал с GDI +. Не забудьте обратить вспять поворот после рисования изображения.
Он делает, но не без обрезки. – Bloodyaugust
См.: Http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-rotate – Michael
Один из комментариев решает проблему отсечения, но не (точно) вращается вокруг центральной точки. См. Комментарий анонимного от 23.03.2009 - 22:23. – Bloodyaugust
Самый быстрый способ заключается в том, чтобы использовать небезопасные вызовы для управления памятью изображений напрямую с помощью LockBits
. Это звучит страшно, но это довольно прямолинейно. Если вы ищете LockBits, вы найдете множество примеров, таких как here.
Интересный бит:
BitmapData originalData = originalBitmap.LockBits(
new Rectangle(0, 0, originalWidth, originalHeight),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppRgb);
После того как вы BitmapData вы можете передать пиксели и отобразить их в новое изображение (опять-таки с помощью LockBits). Это значительно быстрее, чем использование API Graphics
.
BTW правильный (и медленный) способ сделать это с использованием графического интерфейса без обрезки - http://stackoverflow.com/questions/2352804/how-do-i-prevent-clipping-when-rotating-an -image-в-с. – TheCodeKing
Первый (непринятый) ответ - это то, что я предполагаю, что вы имеете в виду? – Bloodyaugust
Я наградил вас щедростью, потому что вы привели меня к моему окончательному ответу, хотя это был не LockBits. Оказывается, мне пришлось использовать только безопасный код ... meh. – Bloodyaugust
Этот ответ возвращает как смещение, на которое он должен быть нарисован, так и изображение, которое было повернуто. Он работает, воссоздавая новое изображение до размера, которое должно быть без обрезки углов. Первоначально он был написан Хисенбургом из чата # C# IRC и Bloodyaugust.
public static double NormalizeAngle(double angle)
{
double division = angle/(Math.PI/2);
double fraction = Math.Ceiling(division) - division;
return (fraction * Math.PI/2);
}
public static Tuple<Image,Size> RotateImage(Image img, double rotationAngle)
{
double normalizedRotationAngle = NormalizeAngle(rotationAngle);
double widthD = img.Width, heightD = img.Height;
double newWidthD, newHeightD;
newWidthD = Math.Cos(normalizedRotationAngle) * widthD + Math.Sin(normalizedRotationAngle) * heightD;
newHeightD = Math.Cos(normalizedRotationAngle) * heightD + Math.Sin(normalizedRotationAngle) * widthD;
int newWidth, newHeight;
newWidth = (int)Math.Ceiling(newWidthD);
newHeight = (int)Math.Ceiling(newHeightD);
Size offset = new Size((newWidth - img.Width)/2,(newHeight - img.Height)/2);
Bitmap bmp = new Bitmap(newWidth, newHeight);
Graphics gfx = Graphics.FromImage(bmp);
//gfx.Clear(Color.Blue);
gfx.TranslateTransform((float)bmp.Width/2, (float)bmp.Height/2);
gfx.RotateTransform((float)(rotationAngle/Math.PI * 180));
gfx.TranslateTransform(-(float)bmp.Width/2, -(float)bmp.Height/2);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.DrawImage(img, new PointF((bmp.Width/2 - img.Width/2), (bmp.Height/2 - img.Height/2)));
gfx.Dispose();
return new Tuple<Image,Size>(bmp,offset);
}
Hello! Любые последующие действия? Что вы в конечном итоге используете? Вы измеряли время перевертывания? Вы сравнили его с EmguCV? Я ищу самый быстрый способ поворота на 90 и 180 градусов изображения на C#. – Pedro77
Для простых поворотов на 90 и 180 градусов обязательно используйте GDI +. Он имеет поворот на 90 градусов. Для произвольных углов используйте LockBits. – Bloodyaugust