Archives du mot-clé MATLAB

Afficher une photo avec la bonne orientation dans MATLAB

Prenons trois photos d’un même objet prises avec trois orientations de l’appareil photo.
robot-1
robot-3
robot-2

La plupart des logiciels détectent automatiquement l’orientation de la photo et affiche l’objet dans sa position naturelle. Ce n’est pas le cas de MATLAB.

Nous allons donc voir comment afficher automatiquement une photo avec la bonne orientation dans MATLAB. Pour ce faire, nous nous intéresserons à des données complémentaires codées dans le fichier JPEG.

Affichage des photos avec MATLAB

Avec MATLAB, pour afficher une image stockée dans un fichier JPEG, on utilise les fonctions imread et image.

Voici le code MATLAB qui lit les fichiers et affiche les images 

filename = {'robot-1.JPG' 'robot-2.JPG' 'robot-3.JPG'};

figure

for n = 1:3
    X = imread(filename{n}, 'jpg');
    subplot(3,1,n)
    image(X)
    axis image off
end

Voici le résultat :
photos-matlab-1
L’orientation des photos n’est pas automatiquement prise en compte par MATLAB.

Les métadonnées EXIF

En plus de la photo en elle-même, l’appareil photo (ou le smartphone) enregistre d’autres informations dans le fichier JPEG. Ces informations sont connues sous le nom de métadonnées EXIF. Plus d’informations sur la page Wikipédia  Exchangeable image file format.

Pour accéder à ces informations avec MATLAB, on utilise la fonction imfinfo (ou la fonction exifread avec les anciennes versions de MATLAB).

Par exemple :

f = imfinfo('robot-1.JPG')

renvoi :

f =

            Filename: 'C:\Users\Jerome\Desktop\robot-1.JPG'
         FileModDate: '04-May-2016 14:14:26'
            FileSize: 92456
              Format: 'jpg'
       FormatVersion: ''
               Width: 640
              Height: 480
            BitDepth: 24
           ColorType: 'truecolor'
     FormatSignature: ''
     NumberOfSamples: 3
        CodingMethod: 'Huffman'
       CodingProcess: 'Sequential'
             Comment: {}
                Make: 'Panasonic'
               Model: 'DMC-FZ18'
         Orientation: 1
         XResolution: 72
         YResolution: 72
      ResolutionUnit: 'Inch'
            Software: 'Ver.1.0  '
            DateTime: '2016:05:04 14:14:26'
    YCbCrPositioning: 'Co-sited'
       DigitalCamera: [1x1 struct]
         UnknownTags: [2x1 struct]
       ExifThumbnail: [1x1 struct]

On remarque la métadonnées Orientation qui, comme son nom l’indique, stocke l’orientation de l’appareil lors de la prise de vue. Ce champs prend une valeur entre 1 et 8 selon la liste suivante :

  • 1 = Horizontal (normal)
  • 2 = Mirror horizontal
  • 3 = Rotate 180
  • 4 = Mirror vertical
  • 5 = Mirror horizontal and rotate 270 CW
  • 6 = Rotate 90 CW
  • 7 = Mirror horizontal and rotate 90 CW
  • 8 = Rotate 270 CW

Les valeurs qui nous intéressent ici sont 1, 6 et 8.

Prise en compte automatique de l’orientation des photos

Vous l’aurez maintenant compris, il faut donc utiliser imfinfo en plus des fonctions imread et image.

Voici le code :

filename = {'robot-1.JPG' 'robot-2.JPG' 'robot-3.JPG'};
figure

for n = 1:3

    X = imread(filename{n}, 'jpg');
    f = imfinfo(filename{n});
    subplot(3,1,n)
    if f.Orientation == 1
        image(X)
    elseif f.Orientation == 6
        X = rot90(X, -1);
        image(X)
    elseif f.Orientation == 8
        X = rot90(X, 1);
        image(X)
    end
    axis image off
end

Ce qui donne :
photos-matlab-2
L’orientation de chaque photo est maintenant bien prise en compte par MATLAB.

Conclusion

Vous savez maintenant comment afficher automatiquement vos photos avec la bonne orientation dans MATLAB en utilisant imfinfo.

Vous trouverez sans doute d’autres informations utiles dans les métadonnées EXIF, n’hésitez pas à partager vos expériences en commentaire de ce billet.

Quand MATLAB et fprintf ne regardent pas dans la même direction…

La fonction fprintf de MATLAB est très utile pour contrôler l’écriture de données dans un fichier texte. Sa syntaxe est la suivante :

fprintf(fileid, format, A)

Le premier argument fileid est l’identifiant du fichier renvoyé par la fonction fopen. Le deuxième argument format gère le formatage de l’écriture. C’est l’argument le plus compliqué à maitriser et il faudra souvent se référer à la documentation pour savoir quel formatage utiliser. Le dernier argument A est le tableau de données à écrire dans le fichier.

Il y a une subtilité à connaitre, même pour des cas d’utilisation de fprintf relativement simple. C’est ce que je vais vous présenter maintenant.

Le problème

Ecrire dans un fichier texte le tableau suivant :

M = [1 2 ; 3 4 ; 5 6]

Soit :

M =

     1     2
     3     4
     5     6

Le contenu du fichier doit donc être le suivant :

1 2
3 4
5 6

Comme un fichier texte s’écrit ligne après ligne (en séparant chaque ligne avec un retour à la ligne), on serait tenté d’écrire le code suivant :

fid = fopen('test.txt', 'wt');
fprintf(fid, '%d %d\n', M);
fclose(fid);

concise-writer-calvin

%d signifie que la valeur à écrire sera un entier. On met deux fois ce format car le tableau a deux colonnes. Puis on demande à fprintf de passer à la ligne avec \n. fprintf répète ensuite ce motif tant qu’il y a des valeurs à écrire. En faisant cela, on ne tient pas compte du nombre de lignes du tableau. Ce qui est très pratique si ce nombre n’est pas constant entre deux appels à fprintf.

En exécutant le code ci-dessus, le fichier texte contient :

1 3
5 2
4 6

Aïe ! Cela ne correspond pas du tout au tableau initial. Les valeurs semblent mélangées.

Les raisons

Le code précédent est faux car il y a une différence fondamentale entre MATLAB et la fonction fprintf.

Le stockage en mémoire des tableaux par MATLAB est particulier. Les valeurs sont stockées dans un vecteur où elles sont toutes contiguës (il n’y a pas d’élément vide entre elles). MATLAB les stocke colonne par colonne (1ère colonne, 2ème colonne, 3ème colonne…). Lire à ce sujet : Stockage des matrices en mémoire.

Le tableau suivant :

M =

     1     2
     3     4
     5     6

est donc stocké comme ceci en mémoire :

     1 3 5 2 4 6

Pourquoi ce choix me direz-vous ? Eh bien parce que MATLAB était initialement écrit en Fortran. Et que les tableaux sont définis colonne par colonne dans ce langage. Donc fprintf prend ces valeurs dans cet ordre et il est alors normal de trouver le 1 et le 3 sur la première ligne du fichier, suivi du 5 et du 2 sur la deuxième ligne et pour finir, du 4 et du 6 sur la dernière.

D’accord, mais les concepteurs de MATLAB auraient facilement pu prendre ceci en compte et, sans tenir compte de l’ordre de stockage par MATLAB, créer une fonction fprintf respectant un passage du tableau sous sa forme naturelle.

Oui mais voila, en 1984, MATLAB a été réécris en langage C. La fonction fprintf de MATLAB repose donc directement sur la fonction homonyme en C (voir les références en bas de la documentation).

Et alors, pourquoi vous parler de Fortran et de C ? Eh bien parce que, en langage C, les tableaux sont définis ligne par ligne.

Si MATLAB utilisait la convention de stockage du C, le code suivant fonctionnerait donc :

fprintf(fid, '%d %d\n', M);

Or ce n’est pas le cas. La fonction fprintf n’a donc pas un comportement naturel pour l’écriture des tableaux de MATLAB.

Les solutions

La première solution consiste à prendre en compte ce problème dès la conception du code et à créer le tableau suivant :

M = [1 3 5 ; 2 4 6];

Soit :

M =

     1     3     5
     2     4     6

Il n’est malheureusement pas toujours envisageable de créer le tableau de cette manière.

La deuxième solution consiste alors à transposer le tableau passé à fprintf. C’est à dire à permuter les lignes et les colonnes du tableau :

M = [1 2 ; 3 4 ; 5 6];
M = M.';

Le tableau devient donc :

M =

     1     3     5
     2     4     6

On peut ensuite faire :

fprintf(fid, '%d %d\n', M);

Ou directement avec le tableau d’origine :

fprintf(fid, '%d %d\n', M.');

La fonction fprintf écrira donc d’abord les valeurs 1 et 2 sur une ligne du fichier, puis 3 et 4 sur une autre, pour finir avec 5 et 6 sur la dernière.

Conclusion

Vous savez maintenant comment écrire correctement un tableau dans un fichier texte avec un seul appel à fprintf depuis MATLAB.

fprintf reste une fonction difficile à manipuler. N’hésitez pas à me poser des questions ou à me soumettre des suggestions à propos de cette fonction en commentaire. Je pourrai toujours faire d’autres billets au sujet de cette fonction.

Sortie du livre « Accelerating MATLAB Performance »

Le nouveau livre de Yair Altman (Undocumented MATLAB), vient de paraître :

Couverture du livre Accelerating MATLAB Performance

Au sommaire :

  • CHAPTER 1: Introduction to Performance Tuning
  • CHAPTER 2: Profiling MATLAB Performance
  • CHAPTER 3: Standard Performance-Tuning Techniques
  • CHAPTER 4: MATLAB-Specific Techniques
  • CHAPTER 5: Implicit Parallelization (Vectorization and Indexing)
  • CHAPTER 6: Explicit Parallelization Using MathWorks Toolboxes
  • CHAPTER 7: Explicit Parallelization by Other Means
  • CHAPTER 8: Using Compiled Code
  • CHAPTER 9: Memory-Related Techniques
  • CHAPTER 10: Graphics and GUI
  • CHAPTER 11: I/O Techniques

D’après l’auteur :

MATLAB est souvent perçu comme une plate-forme appropriée pour le prototypage et la modélisation, mais pas pour les applications « sérieuses ». L’un des principaux reproches est que MATLAB est tout simplement trop lent.

« Accelerating MATLAB Performance » vise à corriger cette perception, en décrivant de multiples façons d’améliorer grandement la vitesse des programmes MATLAB.

Plus d’informations : Accelerating MATLAB Performance book

J’espère pouvoir bientôt lire cet ouvrage. Je ne manquerai pas de publier une critique sur la page Livres de la rubrique MATLAB.

Pour mémoire, Yair Altman est également l’auteur du livre Undocumented Secrets of MATLAB-Java Programming