Partage
  • Partager sur Facebook
  • Partager sur Twitter

Manpulation d'image

Sujet résolu
    17 mars 2017 à 10:44:22

    Bonjour,

    Pour un projet d'info, je dois pouvoir créer un programme qui récupère un fichier .bmp (image bitmap) et qui la manipule avec des entrées/sorties binaires pour pouvoir faire de la rotation, de l'agrandissement/rétrécissement, de la modification, et du renforcement des bords avec matrice de convolution.

    Je dois coder tout le programme sans utiliser la classe bitmap mais je n'arrive pas à réaliser la première étape, c'est-à-dire que je n'arrive pas à obtenir une matrice avec les valeurs des pixels pour pouvoir agir dessus.

    Merci de votre attention.

    • Partager sur Facebook
    • Partager sur Twitter
      17 mars 2017 à 14:02:44

      Bonjour,

      Sans ton code, on va avoir du mal a voir ce qui ne vas pas...

      • Partager sur Facebook
      • Partager sur Twitter
      ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **
        18 mars 2017 à 20:25:30

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        
        namespace ProjetInfo
        {
            class MyImage
            {
                public int Taille { get; private set; }
                public int TailleOffset { get; private set; }
                public int Largeur { get; private set; }
                public int Hauteur { get; private set; }
                public int[,] MatriceRVB { get; private set; }
        
                public MyImage(byte[] myfile)
                {
        
                }
        
                
            }
                           

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.IO;
        
        namespace ProjetInfo
        {
            class Program
            {
                static void Main(string[] args)
                {
                    byte[] file = File.ReadAllBytes(@"C: \Users\Blackpeurs\Documents\Visual Studio 2015\Projects\ProjetInfo\ProjetInfo\Images Tests\Test003.bmp");
                    Console.WriteLine("HEADER \n\n"); //entête
                    for (int i = 0; i < 14; i++)
                        Console.Write(file[i] + ' ');
                    Console.WriteLine("\nHEADER INFO \n\n");
                    for (int i = 14; i < 54; i++)
                        Console.Write(file[i] + ' ');
                    Console.WriteLine("\nIMAGE \n\n");
                    for (int i = 54; i < file.Length; i++)
                        Console.Write(file[i] + "\t");
                    Console.ReadKey();
                }
            }
        }
        }

        J'essaye de comprendre comment passer de mon fichier .bmp à une matrice RVB dans laquelle je pourrais faire des manipulations pour obtenir les résultats décrits dans mon premier post.

        -
        Edité par Itachi-Uchiha 18 mars 2017 à 20:29:48

        • Partager sur Facebook
        • Partager sur Twitter
          18 mars 2017 à 21:36:41

          Ben il va te falloir étudier le format bmp... direction le wiki?
          • Partager sur Facebook
          • Partager sur Twitter
          ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **
            25 mars 2017 à 16:31:18

            C'est ce que j'ai fais mais je n'arrive pas à comprendre, c'est pour ça que j'ai crée ce sujet. Si tu n'as pas l'intention de m'aider, inutile de répondre.
            • Partager sur Facebook
            • Partager sur Twitter
              27 mars 2017 à 11:30:35

              > je n'arrive pas à comprendre

              Quoi au juste ?

              > Si tu n'as pas l'intention de m'aider, inutile de répondre.

              Si tu veux pas apprendre, inutile de poser des questions.

              Rembarrer l'aidant le plus actif du forum, est-ce vraiment finaud ?

              Ayez des questions précises.

              Si vous n'y arrivez pas, donnez-nous les clés pour la préciser.

              • Partager sur Facebook
              • Partager sur Twitter
              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                27 mars 2017 à 13:38:15

                Itachi-Uchiha a écrit:

                C'est ce que j'ai fais

                Peut-être que la boule de cristal de Breizhbugs ne fonctionne plus. Ou peut-être juste qu'il ne faut pas partir du principe qu'il aurait pu deviner ce que tu as fait ou non alors que tu ne l'as pas précisé. Ce que d'ailleurs, tu aurais dû faire dès ton premier message.

                Ensuite, puisque tu connais la structure d'un fichier bmp et que tu es capable de lire les octets d'un fichier (d'après ton code), tu sais certainement comment obtenir la largeur et la hauteur de ton image. Donc tu peux déjà instancier ta matrice. Ensuite, vu que tu sembles également savoir faire des boucles, tu dois être capable de la remplir.

                Donc où est ton problème ?

                • Partager sur Facebook
                • Partager sur Twitter
                Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
                  27 mars 2017 à 18:28:45


                  Ensuite, puisque tu connais la structure d'un fichier bmp et que tu es capable de lire les octets d'un fichier 
                  (d'après ton code), tu sais certainement comment obtenir la largeur et la hauteur de ton image.
                  Donc tu peux déjà instancier ta matrice. Ensuite, vu que tu sembles également savoir faire des boucles, 
                  tu dois être capable de la remplir.

                  Justement, je n'arrive pas à comprendre comment remplir la matrice.

                  using System;
                  using System.Collections.Generic;
                  using System.Linq;
                  using System.Text;
                  using System.Threading.Tasks;
                  using System.IO;
                  
                  namespace ProjetInfo
                  {
                      class MyImage
                      {
                          public int Taille { get; private set; }
                          public int TailleOffset { get; private set; }
                          public int Largeur { get; private set; }
                          public int Hauteur { get; private set; }
                          public int[,] MatriceRVB { get; private set; }
                          public byte[] MyFile { get; private set; }
                  
                  
                          public MyImage(string file)
                          {
                  
                              MyFile = File.ReadAllBytes(file); //On lit l'image
                  
                              //On extrait les infos hauteur et largeur
                              byte[] largeur = new byte[4];
                              byte[] hauteur = new byte[4];
                              for (int i = 0; i <= 4; i++)
                              {
                                  largeur[i] = MyFile[i + 18];
                                  hauteur[i] = MyFile[i + 22];
                              }
                  
                              //On les convertie
                              Largeur = Convertir_Endian_To_Int(largeur);
                              Hauteur = Convertir_Endian_To_Int(hauteur);
                  
                              int indice = 0;
                              for (int ligne = 0; ligne < Hauteur; ligne++)
                              {
                                  for (int colonne = 0; colonne < Largeur; colonne += 3)
                                  {
                                      MatriceRVB[ligne, colonne] = MyFile[indice];
                                      indice++;
                                  }
                              }
                  
                          }
                  
                          public int Convertir_Endian_To_Int(byte[] tab)
                          {
                              if (BitConverter.IsLittleEndian) //l'octet le moins significatif est stocké en premier
                              {
                                  Array.Reverse(tab); //On renverse l'ordre
                              }
                  
                              int valeur = BitConverter.ToInt32(tab, 0); //Le deuxième argument spécifie l'index de début
                              return valeur;
                          }
                  



                  Je ne pense pas que mon remplissage de la matrice est bon. En fait, je ne comprend pas concrètement comment passer de ce fichier d'octets en matrice RVB.

                  -
                  Edité par Itachi-Uchiha 27 mars 2017 à 18:30:03

                  • Partager sur Facebook
                  • Partager sur Twitter
                    27 mars 2017 à 19:29:56

                    Les headers d'un fichier BMP, c'est pas juste pour décorer, remplit à ras-bord d'informations, toutes nécessaires pour correctement interpréter le contenu du fichier.

                    Je trouve que votre code de "déchiffrage" des en-tête est quelque peu succinct.

                    C'est pas juste la lecture random de 2 fois 32bits à des offset en dure, très très loin de là.

                    https://en.wikipedia.org/wiki/BMP_file_format

                    Donc, si vous avez lu et compris les spécifications du format, vous devez être au moins conscient que votre début de décodage des en-têtes est pour le moins très peu fiable.

                    Après, en faisant l’abstraction que vous avez un format d'image correspondant à vos multiple assertion, pourquoi votre indice ligne 38 commence en 0 ???

                    C'est pas faute d'avoir toute une collection d'en-têtes qui comment en 0 pour vous dissuader de relire les mêmes octets pour votre matrice.

                    Vous avez compris de travers l'utilisation de "IsLittleEndian". La documentation indique que toutes les longueurs sont en LittleEndian, c'est donc quand BitConverter.IsLittleEndian est FAUX qu'il faut "retourner" les octets.

                    Au vu du code, la remarque de @breizhbugs est plus que justifié.

                    Le format BMP est loin d'être le plus simple, le prenez pas la documentation par-dessus la jambe.

                    Donc :

                    - vos calculs d'offset des champs hauteur et largeur sont assez approximatifs.

                    - vous vous trompez complètement sur le calcul de la hauteur et de la largeur

                    - vous ne tenez pas compte de la présence des en-têtes pour calculer le début des pixels

                    - les informations dans les en-têtes nécessaire au décodage, vous vous en battez les gamètes, normal que vous ayez mal à la tête. :-°

                    - les notions de padding de ligne, vous en tapez le coquillard, donc concrètement, vous pensez que les spécifications du format, c'est pour les loosers, comme nous ?

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                      28 mars 2017 à 17:55:32

                      C'est vrai que j'ai mal utilisé la méthode BitConverter.IsLittleEndian, retourner les octets quand celle-ci me renvoie faux me donne des valeurs de largeur et hauteur plus raisonnables. D'ailleurs, je me suis inspiré de l'exemple ci-dessous et je suis convaincu qu'il y est indiqué le contraire (voir 1er exemple)

                      https://msdn.microsoft.com/fr-fr/library/bb384066.aspx

                      Ensuite, ce je comprends pas trop ce que vous voulez dire quand vous dites que vous je ne prends pas assez en compte les entêtes ou que mes calculs de largeur et hauteur sont approximatifs.

                      Pour l'instant, je m'occupe uniquement des images bitmap 24 bits. J'ai laissé des valeurs en dur pour les tests.

                      J'ai pensé faire un tableau de tableau (tableau 2D), comme j'ai calculé la taille de la partie correspondant aux pixels.

                      Du coup voilà mon code:

                      using System;
                      using System.Collections.Generic;
                      using System.Linq;
                      using System.Text;
                      using System.Threading.Tasks;
                      using System.IO;
                      
                      namespace ProjetInfo
                      {
                          public class MyImage
                          {
                              public int TailleFichier { get; private set; } 
                              public int TailleEntete { get; private set; } //taille de l'entête
                              public int LargeurImage { get; private set; }
                              public int HauteurImage { get; private set; }
                              public int NbBitsParPixel { get; private set; }
                              public int[][] MatriceRVB { get; private set; }
                              public byte[] MyFile { get; private set; }
                      
                      
                              public MyImage(string file)
                              {
                      
                                  MyFile = File.ReadAllBytes(file); //On lit l'image
                      
                                  //On extrait les octets représentant les infos du fichier et on les stocke dans des tableaux
                                  byte[] tailleEntete = new byte[4];
                                  byte[] largeurImage = new byte[4];
                                  byte[] hauteurImage = new byte[4];
                                  byte[] nbBitsParPixel = new byte[2];
                      
                                  for (int i = 0; i < 4; i++)
                                  {
                                      tailleEntete[i] = MyFile[i + 14];
                                      largeurImage[i] = MyFile[i + 18];
                                      hauteurImage[i] = MyFile[i + 22];
                                      if (i < 2)
                                      {
                                          nbBitsParPixel[i] = MyFile[i + 24];
                                      }
                            
                                  }
                      
                                  //On les convertie en entier
                                  LargeurImage = Convertir_Endian_To_Int(largeurImage);
                                  HauteurImage = Convertir_Endian_To_Int(hauteurImage);
                                  NbBitsParPixel = Convertir_Endian_To_Int(nbBitsParPixel);
                      
                                  //On les utilise pour définir la taille de notre tableau de tableau
                                  int rowSize = ( (NbBitsParPixel * LargeurImage + 31) / 32 ) * 4;
                                  int pixelArraySize = rowSize * Math.Abs(HauteurImage);
                      
                                  MatriceRVB = new int[pixelArraySize][];
                      
                                  int indice = 54;
                                  for (int i = 0; i < pixelArraySize; i++)
                                  {            
                                      MatriceRVB[i] = new int[3]; //RVB
                                      for (int j = 0; j < 3; j++)
                                      {
                                          MatriceRVB[i][j] = MyFile[indice]; //j = 0 --> valeur du bleu, j=1 --> valeur du vert
                                          //j = 1 --> valeur du rouge
                                      }
                                      indice++;
                                  }
                              }
                      
                              public int Convertir_Endian_To_Int(byte[] tab)
                              {
                                  if (BitConverter.IsLittleEndian == false) //si l'octet le moins significatif n'est pas stocké en premier
                                  {
                                      Array.Reverse(tab); //On renverse l'ordre
                                  }
                                  int valeur = 0;
                                  if(tab.Length == 2)
                                      valeur = BitConverter.ToInt16(tab, 0); //Le deuxième argument spécifie l'index de début
                                  else
                                      valeur = BitConverter.ToInt32(tab, 0); 
                                  return valeur;
                              }
                      
                              
                      
                      
                      
                          }
                                         
                      }
                      



                      Je suis pas sûr que pixelArraySize correspond bien à file.Length - 54 (qu'à la fin de la boucle, on a bien parcouru tous les pixels). J'ai utilisé la formule qui est donnée dans le fichier wikipédia.

                      Je sais pas non plus si ça pose problème de remplir ma matrice comme ça alors que ça commence en bas à gauche de l'image (le premier pixel de la matrice est en bas à gauche).



                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 mars 2017 à 18:56:08

                        Déjà, avec ton code, tu perds la notion de multi-dimensionnalité de ton image.

                        Concernant tes lignes entre 56 et 65, tu fais évoluer i, j et indice en parallèle, ce qui signifie donc qu'il faudrait que chaque pixel soit forcément à la suite, ce qui n'est pas nécessairement le cas :

                        "Padding bytes (not necessarily 0) must be appended to the end of the rows in order to bring up the length of the rows to a multiple of four bytes."

                        Par exemple, si ton fichier est en 24 bpp et que ta largeur n'est pas un multiple de 4, tu auras un padding.

                        Quant à ton tableau pour contenir le rouge, le vert et le bleu à trois indices séparés, ce serait beaucoup plus simple et propre de faire une classe Couleur qui s'occupera elle-même de convertir tes N bits en une couleur avec ses trois (ou 4) composantes. 

                        Pour résumer :

                        • Oublie ton int[][] et crée un Couleur[,] dont tu connais la largeur (celle de l'image) et la hauteur (la valeur absolue de l'image)
                        • Fais une double boucle pour parcourir et alimenter ton tableau à 2 dimensions, puis calcule la position du pixel correspondant dans ton pixel.
                        • Envoie alors les bits en question à un constructeur de ta classe Couleur, qui devra transformer ces bits en R, G et B.
                        Et comme je suis de bonne humeur, je t'ai fait un bout de code
                        int octetsParLigne = ((bitsParPixel * largeur + 31) / 32) * 4;
                        int firstDataIndex = 54;
                        // Au cas où tu te poserais la question, ce calcul permet d'avoir
                        // la largeur en octets (8 bits), arrondie au multiple de 4 octets supérieur
                        
                        int octetsParPixel = bitsParPixel / 8; // Ne marchera donc 
                        // qu'avec des bitmaps en 8, 16, 24 ou 32 bpp
                        
                        for (int x = 0; x < largeur; x++)
                        {
                            for (int y = 0; y < Math.Abs(hauteur); y++)
                            {
                                int lineInFile = hauteur < 0 ? y : hauteur - y - 1;
                                var index = firstDataIndex + lineInFile * octetsParLigne + x * octetsParPixel; // Attention : la partie
                                byte[] pixelData = new byte[octetsParPixel];
                                for (int bit = 0; bit < octetsParPixel; bit++)
                                {
                                    pixelData[bit] = MyFile[index + bit];
                                }
                                tab[x, y] = new Couleur(pixelData, bitsParPixel);
                            }
                        }
                        Je n'ai pas testé. Ce code. Je n'ai lu la doc du bmp qu'en diagonale.
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
                          30 mars 2017 à 10:54:07

                          Ok, j'ai réussi à créer ma matrice de pixels en créant une classe couleur comme tu l'as dit avec les attributs rouge, vert et bleu. J'ai bien assimilé le format bitmap. J'ai testé les infos récoltés et les résultats que j'obtiens.

                          Je place ce sujet en mode "Résolu". Si j'ai besoin d'aide pour la suite, je créerai un nouveau sujet.

                          Merci pour votre aide. Je m'excuse pour mes propos déplacés, j'étais frustré de ne pas avancer.

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Manpulation d'image

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown