Rotation d'image sans Graphics.RotateTransform

Résolu
Utilisateur anonyme - 14 sept. 2007 à 05:48
 Utilisateur anonyme - 18 sept. 2007 à 12:31
Bonjour,

Dans le but de faire une application plus étendue, je souhaite faire une rotation d'image sans utiliser Graphics.RotateTransform qui fait pourtant vite et bien les choses. Doncm je me suis lancé dans la réalisation d'une fonction de rotation de mon image, si la fonction est correcte, elle est particulièment lente, la faute aux fonctions GetPixel et SetPixel que je ne sais pas comment remplacer. Voici le bout de code où je procède à cette étape :

                    try
                    {
                        Color color = bmp.GetPixel(xk, yk);
                        rotate.SetPixel(x, y, color);
                    }
                    catch
                    {
                        rotate.SetPixel(x, y, Color.White);
                    }

C'est une simple rotation avec la technique tout simple du plus proche voisin. La technique n'est pas ici un problème mais je souhaite accélérer les temps de calcul qui sont affreusement longs. Si vous pouviez m'aider à réécrire ce bout de code de façon plus adéquate, je vous en serai reconnaissant.

7 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
14 sept. 2007 à 07:11
Salut, le principe est de fixer le bitmap en mémoire avec la fonction Bitmap.LockBits pour accèder aux pixels via les pointeurs..

Rien de mieux que les tutos de Tkfé :

http://blogs.developpeur.org/tkfe/archive/2006/10/19/Manipuler-les-images-en-VB.NET.aspx
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 sept. 2007 à 17:37
Salut, bien plus rapide que GetPixel/SetPixel j'imagine quand même ?

- Essayes de sortir un maximum de calculs de la boucle.
- Utilise des constantes à la place de variables quand c'est possible.
- Remplace l'appel à la propriété image.Width par un variable.

Si c'est encore très long c'est peut être que tu tombes dans ton catch.. une execption c'est très couteux en temps CPU.

Mais surtout, avec les pointeurs, à aucun moment tu ne dois écrire ou lire dans une plage mémoire en dehors de ton bitmap, ce try/catch n'est pas du tout une bonne solution.
3
Utilisateur anonyme
17 sept. 2007 à 10:21
Merci pour le lien, je connaissais la technique mais comme je ne suis pas très bon, je ne savais pas l'utiliser pour l'application (légèrement) plus compliquée que je développe ici. C'est très bien expliqué et ça me permet de comprendre, ce qui est tout de même très bien (en tout cas, mieux que le copier/coller que j'avais fait dans un de mes programmes précédents).

Merci encore.
0
Utilisateur anonyme
17 sept. 2007 à 11:40
J'ai réussi à implémenter le code sans trop de difficultés, cependant, le temps de traitement reste long quand je procède au traitement de mes deux images, il est probable que j'ai mal codé ce qui ralentirait le processus, je vous montre mon bout de code et si vous pouviez le critiquer, et éventuellement trouver l'erreur (ou les erreurs) que j'ai faite(s), cela m'aiderait grandement. Pour la petite anecdote, ce code est censé faire ce que fait la fonction Graphics.RotateTransform mais avec une interpolation par la technique du plus proche voisin (donc encore moins bien que la fonction d'origine) :

            // To work fast with the original image by using pointer and method LockBits
            // This code works with images in PixelFormat.Format32bppArgb
            BitmapData bmpOrigin = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.ReadOnly, image.PixelFormat);

            // Create the new rotated picture
            Bitmap rotate = new Bitmap(image.Width, image.Height);
            BitmapData bmpFinal = rotate.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.WriteOnly, image.PixelFormat);

            // Manipulate each byte
            uint* oldPixel = (uint*)(void*)bmpOrigin.Scan0;
            uint* newPixel = (uint*)(void*)bmpFinal.Scan0;

            for (int y = 0; y < image.Width; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    // Calcute coordonates on original picture
                    int ox = (int)(x * cos - y * sin);
                    int oy = (int)(y * cos + x * sin);

                    // Calcute pixel number to proceed
                    int oldPos = ox + (150 * oy);
                    int newPos = x + (150 * y);

                    try
                    {
                        // Give the new pixel color which is the same as in the
                        // original picture with its old coordonates
                        newPixel[newPos] = oldPixel[oldPos];
                    }
                    catch
                    {
                        // If the old pixel doesn't exist, put a white background
                        newPixel[newPos] = 0xFFFFFFFF;
                    }
                }
            }
            // Dispose resources
            rotate.UnlockBits(bmpFinal);
            image.UnlockBits(bmpOrigin);
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Utilisateur anonyme
18 sept. 2007 à 03:15
Avec le try catch, c'était presque aussi long que la méthode GetPixel/SetPixel !!! C'est vrai qu'en l'enlevant, on gagne beaucoup, j'ai remplacé par un if et la différence est énorme, je ne savais pas que cela était si couteux (ignorant que je suis). Ce n'est pas encore aussi rapide que la méthode Graphics.RotateTransform mais ça, c'est mon problème.

Merci pour l'aide apportée, les deux réponses répondent très bien à toutes mes questions.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
18 sept. 2007 à 10:57
n'oublie pas de remplacer:

for ( int y = 0; i < Image.Height; y++ )
   for ( int x = 0; < Image.Width; x++ )

par

int width = Image.Width;
int height = Image.Height;

for ( int y = 0; i < height; y++ )
   for ( int x = 0; < width; x++ )

Car une propriété c'est la même chose qu'une fonction.. pour un bitmap de 640x480 c'est comme si tu appelais 307200 fois une méthode. : /
0
Utilisateur anonyme
18 sept. 2007 à 12:31
Merci pour cette précision, j'avais déjà pris note de la remarque et c'est vrai que ça fait quelques instructions supplémentaires... par contre, les calculs de la boucle sont, je pense, impossible à sortir de là (sinon, ils ne seraient pas dans la boucle).

Je vais essayer de lui faire faire une interpolation bilinéaire pour que ça soit quand même plus joli et après, je pense aux rotations 3D, j'espère que ça sera assez rapide...
0
Rejoignez-nous