2010-09-21 1 views
3

Для этого есть некоторые алгоритмы looooong и hungry, но пока я не придумал и не нашел что-то особенно быстрое.Каков самый быстрый способ поворота изображения без обрезки его ребер с помощью GDI +?

+0

Hello! Любые последующие действия? Что вы в конечном итоге используете? Вы измеряли время перевертывания? Вы сравнили его с EmguCV? Я ищу самый быстрый способ поворота на 90 и 180 градусов изображения на C#. – Pedro77

+0

Для простых поворотов на 90 и 180 градусов обязательно используйте GDI +. Он имеет поворот на 90 градусов. Для произвольных углов используйте LockBits. – Bloodyaugust

ответ

3

Вот что я в конечном итоге делает (после обширного количества дальнейших исследований, а также полезная ссылка предоставлена ​​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; 
    } 

Ура!

0
void Graphics.RotateTransform(float angle); 

Это должно повернуть изображение на C#. Что он делает вместо этого?

Я не слишком много экспериментировал с GDI +. Не забудьте обратить вспять поворот после рисования изображения.

+0

Он делает, но не без обрезки. – Bloodyaugust

+0

См.: Http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-rotate – Michael

+0

Один из комментариев решает проблему отсечения, но не (точно) вращается вокруг центральной точки. См. Комментарий анонимного от 23.03.2009 - 22:23. – Bloodyaugust

5

Самый быстрый способ заключается в том, чтобы использовать небезопасные вызовы для управления памятью изображений напрямую с помощью LockBits. Это звучит страшно, но это довольно прямолинейно. Если вы ищете LockBits, вы найдете множество примеров, таких как here.

Интересный бит:

BitmapData originalData = originalBitmap.LockBits(
    new Rectangle(0, 0, originalWidth, originalHeight), 
    ImageLockMode.ReadOnly, 
    PixelFormat.Format32bppRgb); 

После того как вы BitmapData вы можете передать пиксели и отобразить их в новое изображение (опять-таки с помощью LockBits). Это значительно быстрее, чем использование API Graphics.

+0

BTW правильный (и медленный) способ сделать это с использованием графического интерфейса без обрезки - http://stackoverflow.com/questions/2352804/how-do-i-prevent-clipping-when-rotating-an -image-в-с. – TheCodeKing

+0

Первый (непринятый) ответ - это то, что я предполагаю, что вы имеете в виду? – Bloodyaugust

+0

Я наградил вас щедростью, потому что вы привели меня к моему окончательному ответу, хотя это был не LockBits. Оказывается, мне пришлось использовать только безопасный код ... meh. – Bloodyaugust

0

Этот ответ возвращает как смещение, на которое он должен быть нарисован, так и изображение, которое было повернуто. Он работает, воссоздавая новое изображение до размера, которое должно быть без обрезки углов. Первоначально он был написан Хисенбургом из чата # 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); 
    }