Rotation d'image sans Graphics.RotateTransform [Résolu]

Utilisateur anonyme - 14 sept. 2007 à 05:48 - Dernière réponse :  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.
Afficher la suite 

7 réponses

Répondre au sujet
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 14 sept. 2007 à 07:11
+3
Utile
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
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 17 sept. 2007 à 17:37
+3
Utile
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.
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Lutinore
Utilisateur anonyme - 17 sept. 2007 à 10:21
0
Utile
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.
Commenter la réponse de Utilisateur anonyme
Utilisateur anonyme - 17 sept. 2007 à 11:40
0
Utile
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);
Commenter la réponse de Utilisateur anonyme
Utilisateur anonyme - 18 sept. 2007 à 03:15
0
Utile
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.
Commenter la réponse de Utilisateur anonyme
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 18 sept. 2007 à 10:57
0
Utile
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. : /
Commenter la réponse de Lutinore
Utilisateur anonyme - 18 sept. 2007 à 12:31
0
Utile
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...
Commenter la réponse de Utilisateur anonyme

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.