zestedesavoir / zds-site

Cœur du projet technique de Zeste de Savoir
https://zestedesavoir.com
Other
269 stars 161 forks source link

Encodage foireux dans les tutoriels #322

Closed firm1 closed 10 years ago

firm1 commented 10 years ago

La magie de python 2 est très probablement sa gestion des caractères. En important le tutoriel de nohar sur la vision par ordinateur il y'a un chapitre que je n'arrive pas à lire, il s'agit de celui-ci.

Je ne sais pas si le problème vient de zmarkdown ou du code de recupération du text, mais le fait est qu'après un décodage en utf8, le parseur markdown n'arrive pas à traduire le texte.

Vous pouvez télécharger l'archive du tuto pour voir le contenu qui est stocké sur le serveur.

Dans ce cas précis, le bout de texte qui est passé à markdown et qui génère l'erreur est celui-ci :

'txt': u'# Notre image de test\n\n\nAvant de commencer \xe0 jouer avec des images, laissez-moi, en guise de pause \xe9tant donn\xe9 que le d\xe9but de ce chapitre \xe9tait plut\xf4t dense, vous pr\xe9senter l\'image que nous allons utiliser pour la plupart de nos tests, **Lena**.\n\n![](/media/galleries/normal/51/b640fd92-96a7-4391-9bb9-23bc573d8653.jpg)\n\nCette image, comme je vous l\'ai d\xe9j\xe0 dit dans le pr\xe9c\xe9dent chapitre, est le petit carr\xe9 de 512\xd7512 pixels le plus c\xe9l\xe8bre du monde de la recherche et de l\'ing\xe9nierie en imagerie, ce qui lui vaut certainement le titre de \xab\xa0Joconde de la vision par ordinateur\xa0\xbb. Voici son histoire.\n\nTout commen\xe7a dans le laboratoire SIPI de la prestigieuse _University of Southern California_, au sein duquel \xe9taient alors men\xe9s les travaux de recherche qui finiraient par aboutir aux standards de compression JPEG et MPEG que nous connaissons tous aujourd\'hui. \n\nPar un beau jour de l\'\xe9t\xe9 1973, trois chercheurs de ce laboratoire \xe9taient affair\xe9s, dans l\'urgence, \xe0 la recherche d\'une image d\'exemple qui soit nouvelle et suffisamment sympathique pour \xeatre publi\xe9e dans l\'article de conf\xe9rence de l\'un de leur coll\xe8gues, concernant les derniers r\xe9sultats de ses recherches dans le domaine de la compression d\'images. C\'est alors qu\'une personne entra dans leur bureau un magazine entre les mains, magazine en page centrale duquel se trouvait la photo d\'une femme, nomm\xe9e Lena. La d\xe9cision ne fut pas longue \xe0 prendre\xa0: nos chercheurs arrach\xe8rent la photographie dudit magazine, la num\xe9ris\xe8rent avec les moyens de l\'\xe9poque, et retaill\xe8rent le r\xe9sultat pour obtenir l\'image carr\xe9e de 512\xd7512 pixels que vous avez sous les yeux.\n\nL\'histoire aurait pu s\'arr\xeater ici, si ce n\'\xe9tait qu\'une vingtaine d\'ann\xe9es plus tard, alors que cette image \xe9tait devenue un standard gr\xe2ce auquel les chercheurs pouvaient comparer leurs algorithmes de compression, et distribu\xe9e de fa\xe7on payante par le SIPI, le magazine d\'origine de la photo se manifesta, relativement f\xe2ch\xe9 de voir sa propri\xe9t\xe9 r\xe9utilis\xe9e sans lui verser ses droits, ce qui marqua aussi, par ailleurs, le d\xe9but d\'une bruyante pol\xe9mique au sein de la communaut\xe9 scientifique. En effet, Lena Sj\xf6\xf6blom n\'est autre que la _miss Playboy_ du mois de novembre 1972\xa0! :)\n\nAujourd\'hui, cette photo est accessible librement et gratuitement, et continue d\'\xeatre la plus utilis\xe9e pour tester des algorithmes de traitement d\'image, non pas \xe0 cause du regard \xe9nigmatique de la demoiselle, mais plut\xf4t en raison du panel complet de textures fines, de surfaces relativement uniformes, de contours et de d\xe9tails qui font sa richesse (\u2026 Bon, probablement aussi parce qu\'elle est jolie, quand m\xeame).\n\nVous pourrez trouver l\'image originale au format TIFF (donc non compress\xe9) [ici](http://www.cs.cmu.edu/~chuck/lennapg/lena_std.tif). C\'est celle que je vous recommande d\'utiliser pour tester vos algos en tous genres, plut\xf4t que le JPEG, \xe9tant donn\xe9 que dans certains cas, la compression JPEG fera appara\xeetre des art\xe9facts ind\xe9sirables dans vos r\xe9sultats.\n\nSur ce, la pause est termin\xe9e.\n\n\n# Plusieurs m\xe9thodes diff\xe9rentes\n\n\nDans le reste de cette sous-partie, nous allons coder, de plusieurs fa\xe7ons possibles, un petit programme qui ouvre une image en niveaux de gris 8 bits, et qui en _inverse_ les pixels. \n\nCela signifie que la transformation que nous allons r\xe9aliser sera la fonction suivante, o\xf9 $\\mathrm{dst}$ est l\'image de r\xe9sultat et $\\mathrm{src}$\xa0l\'image d\'origine\xa0: \n\n$\\mathrm{dst}(x,y) = 255 - \\mathrm{src} (x,y)$\n\nVoici le r\xe9sultat attendu, dans tous les cas, sur la photo de Lena\xa0: \n\n![](/media/galleries/normal/51/30ebaa54-1d43-4dd9-b68e-b1a805ad5ae1.jpg)\n\nPour nous simplifier la vie, nous allons simplement \xe9crire une fonction `inverse` qui prend en argument une `IplImage*` et inverse l\'image contenue _en place_.\n\nVoici le corps du programme sur lequel nous allons travailler. \n\n\n```c hl_lines="12"\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <opencv/cv.h>\n#include <opencv/highgui.h>\n\n/**\n * Inverse une image "en place"\n */\nvoid invert (IplImage* img)\n{\n  assert (img->depth == IPL_DEPTH_8U && img->nChannels == 1);\n  // TODO \n}\n\n/**\n * Ce programme prend deux arguments dont un optionnel:\n * IMAGE:     l\'image \xe0 inverser\n * SAVE_PATH: (optionnel) l\'image dans laquelle sauvegarder le r\xe9sultat\n */\nint main (int argc, char* argv[])\n{\n  IplImage* img = NULL; \n  const char* src_path = NULL;\n  const char* dst_path = NULL;\n  const char* window_title = "Inverse";\n\n  if (argc < 2)\n  {\n    fprintf (stderr, "usage: %s IMAGE [SAVE_PATH]\\n", argv[0]);\n    return EXIT_FAILURE;\n  }\n\n  src_path = argv[1];\n\n   // optionnel: sauvegarde du r\xe9sultat \n   // si un second chemin est pass\xe9 au programme\n  if (argc > 2) \n    dst_path = argv[2];\n\n  if (!(img = cvLoadImage (src_path, CV_LOAD_IMAGE_GRAYSCALE)))\n  {\n    fprintf (stderr, "couldn\'t open image file: %s\\n", argv[1]);\n    return EXIT_FAILURE;\n  }\n\n  invert (img);\n\n  cvNamedWindow (window_title, CV_WINDOW_AUTOSIZE);\n  cvShowImage   (window_title, img);\n  cvWaitKey (0);\n  cvDestroyAllWindows ();\n  \n  if (dst_path && !cvSaveImage (dst_path, img, NULL))\n  {\n    fprintf (stderr, "couldn\'t write image to file: %s\\n", dst_path);\n  }\n  \n  cvReleaseImage(&img);\n  return EXIT_SUCCESS;\n}\n```\nCode:invert.c\n\n\nComme vous le voyez, j\'ai pris soin de m\'occuper de tout l\'aspect cosm\xe9tique \xe0 votre place (chargement de l\'image et conversion en niveaux de gris, enregistrement optionnel, affichage du r\xe9sultat\u2026), de fa\xe7on que nous n\'ayons besoin de nous occuper ensemble que de la fonction `invert`.\n\nVous remarquerez que j\'ai surlign\xe9 la ligne 12, car j\'y utilise la fonction assert que vous n\'avez peut-\xeatre pas encore crois\xe9e. Cette fonction toute simple prend _une condition_ en argument et plante le programme si celle-ci n\'est pas remplie. C\'est une s\xe9curit\xe9 qui permet de d\xe9tecter tout de suite si quelque chose ne fonctionne pas normalement dans votre code. Son autre int\xe9r\xeat, c\'est qu\'une fois que vous avez termin\xe9 de tester votre programme dans tous les sens, vous pouvez gagner un peu en performances en d\xe9sactivant cette fonction (qui deviendra "invisible" pour le compilateur), simplement en utilisant la constante `NDEBUG` \xe0 la compilation. Vous trouverez plus d\'informations \xe0 ce sujet [ici](http://en.wikipedia.org/wiki/Assert.h).\n\nDans notre code, cette ligne permet de s\'assurer que l\'image pass\xe9e en argument \xe0 la fonction `invert` est bel et bien une image en niveaux de gris 8 bits.\n\n\n## La m\xe9thode simple\xa0: les fonctions cvPtr*D\n\n\nPour inverser notre image, il n\'y a pas 36 fa\xe7ons possibles\xa0: il nous suffit, pour chaque paire de coordonn\xe9es $(x,y)$, de r\xe9cup\xe9rer un pointeur sur le pixel correspondant, et d\'op\xe9rer la modification dessus. Ce que nous allons voir jusqu\'\xe0 la fin de cette sous-partie, ce sont trois m\xe9thodes de plus en plus bas niveau pour cela.\n\nPour r\xe9cup\xe9rer un pointeur sur un pixel donn\xe9 d\'une image en niveaux de gris, nous pouvons utiliser la fonction [cvPtr2D](http://opencv.willowgarage.com/documentation/c/core_operations_on_arrays.html#cvPtr2D) dont voici la signature\xa0: \n\n\n```c\n/**\n * R\xe9cup\xe9rer un pointeur sur un \xe9l\xe9ment donn\xe9 d\'un tableau.\n * arguments:\n * - arr: image (ou matrice) \xe0 parcourir\n * - idx0: num\xe9ro de ligne du pixel\n * - idx1: num\xe9ro de colonne du pixel\n * - type: param\xe8tre optionnel de sortie, d\xe9crivant la profondeur\n *         du tableau\n * retourne:\n * un pointeur sur l\'\xe9l\xe9ment du tableau vis\xe9.\n */\nuchar* cvPtr2D (const CvArr* arr, int idx0, int idx1, int* type);\n```\n\n\n**Attention \xe0 l\'ordre des arguments**\xa0: il faut d\'abord passer \xe0 cette fonction _le num\xe9ro de ligne_ du pixel (soit la coordonn\xe9e $y$) puis le num\xe9ro de colonne (la coordonn\xe9e $x$). Le param\xe8tre optionnel `type` ne nous int\xe9resse pas pour l\'instant\xa0: on pourra le laisser \xe0 `NULL` la plupart du temps.\n\nVoici une impl\xe9mentation de la fonction `invert` en utilisant cvPtr2D pour parcourir l\'image.\n\n\n```c\nvoid invert (IplImage* img)\n{\n  int x,y;\n  uchar *p;\n  assert (img->depth == IPL_DEPTH_8U && img->nChannels == 1);\n\n  for (y = 0; y < img->height; ++y)\n  {\n    for (x = 0; x < img->width; ++x)\n    {\n      // r\xe9cup\xe9ration d\'un pointeur sur le pixel de coordonn\xe9es (x,y)\n      p = cvPtr2D (img, y, x, NULL);\n      *p = 255 - *p;\n    }\n  }\n}\n```\n\n\nComme vous le constatez, le code est plut\xf4t direct. Ce qui est int\xe9ressant \xe0 noter, c\'est que la fonction `cvPtr2D` r\xe9alise exactement le petit calcul sur les pointeurs que je vous ai montr\xe9 plus haut. Cela peut \xeatre mis en \xe9vidence en utilisant \xe0 la place la fonction `cvPtr1D`\xa0:\n\n\n```c\n/**\n * Retourne un pointeur sur le pixel de coordonn\xe9e idx.\n */\nuchar* cvPtr1D (const CvArr* arr, int idx, int* type);\n```\n\n\nCette fonction r\xe9alise la m\xeame op\xe9ration que la pr\xe9c\xe9dente, mais en consid\xe9rant cette fois que le tableau pass\xe9 en argument n\'a qu\'une seule dimension. Pour l\'utiliser, il nous faut donc calculer l\'emplacement du pixel vis\xe9 nous-m\xeames, comme ceci\xa0:\n\n\n```c hl_lines="12"\nvoid invert (IplImage* img)\n{\n  int x,y;\n  uchar *p;\n  assert (img->depth == IPL_DEPTH_8U && img->nChannels == 1);\n\n  for (y = 0; y < img->height; ++y)\n  {\n    for (x = 0; x < img->width; ++x)\n    {\n      // r\xe9cup\xe9ration d\'un pointeur sur le pixel de coordonn\xe9es (x,y)\n      p = cvPtr1D (img, y * img->widthStep + x, NULL);\n      *p = 255 - *p;\n    }\n  }\n}\n```\n\n\nLa seule ligne qui change dans ce code est celle surlign\xe9e. Comme vous le voyez, le calcul de l\'indice du pixel reprend exactement ce qui pr\xe9c\xe8de dans ce chapitre.\n\n\n## La m\xe9thode rapide\xa0: l\'acc\xe8s direct au pointeur\n\n\nLe seul inconv\xe9nient de la m\xe9thode pr\xe9c\xe9dente pour parcourir une image, c\'est que l\'indice du pixel est enti\xe8rement recalcul\xe9 \xe0 chaque passage dans la deuxi\xe8me boucle. Il ne devrait pas \xeatre bien compliqu\xe9 de trouver un moyen plus direct pour _scanner_ toute une image, sans avoir besoin d\'une fonction pour cela.\n\nVoici la derni\xe8re impl\xe9mentation compl\xe8te de la fonction `invert` que nous verrons dans ce chapitre\xa0: \n\n\n```c\nvoid invert (IplImage* img)\n{\n  uchar *p, *line;\n  assert (img->depth == IPL_DEPTH_8U && img->nChannels == 1);\n\n  // parcours des lignes de l\'image\n  // on positionne le pointeur "line" sur le d\xe9but de l\'image\n  // et on le fait avancer de la taille d\'une ligne \xe0 chaque it\xe9ration\n  // jusqu\'\xe0 tomber sur l\'octet suivant le dernier pixel de l\'image\n  for (line = (uchar*) img->imageData; \n       line < (uchar*) img->imageData + img->imageSize; \n       line += img->widthStep)\n  {\n    // parcours de la ligne "line"\n    // on positionne le pointeur p sur le d\xe9but de la ligne\n    // et on le fait avancer de la taille d\'un pixel \xe0 chaque it\xe9ration\n    // jusqu\'\xe0 tomber sur le dernier pixel de la ligne\n    for (p = line; p < line + img->width; ++p)\n    {\n      *p = 255 - *p;\n    }\n  }\n}\n```\n\n\nCe code, quoique relativement d\xe9routant de prime abord si vous n\'avez pas l\'habitude de jouer avec les pointeurs de cette fa\xe7on, n\'est pas sp\xe9cialement compliqu\xe9 (les commentaires sont l\xe0 pour vous guider). Je vous conseille de le d\xe9rouler lentement dans votre t\xeate jusqu\'\xe0 ce qu\'il soit clair pour vous, car c\'est ainsi que nous parcourrons nos matrices chaque fois que nous aurons besoin de r\xe9aliser un \xab\xa0_full-scan_\xa0\xbb.\n\n\n## La m\xe9thode qui tue\n\n\nPour les plus coriaces d\'entre vous, voici quand m\xeame une derni\xe8re impl\xe9mentation de la fonction `invert`, tr\xe8s en marge du cadre de ce chapitre, mais que je vous laisse analyser \xe0 titre d\'exercice en vous aidant de la documentation\xa0de la fonction [`cvNot`](http://opencv.willowgarage.com/documentation/c/core_operations_on_arrays.html#not) :\n\n\n```c\nvoid invert (IplImage* img)\n{\n  cvNot (img, img);\n}\n```\n\n:p\n\n*[SIPI]: Signal and Image Processing Institute'
Coy0te commented 10 years ago

A priori, c'est le même bug que j'avais remarqué sur mon tutoriel. Exemple : => http://preprod.zestedesavoir.com/tutoriels/off/51/creez-votre-application-web-avec-java-ee/une-bonne-vue-grace-a-la-jstl/la-bibliotheque-core/?version=ad13748eac87d169cd00a5ba7ed007f07f21002d

Je ne donne qu'un exemple ici, mais ça me le fait dans beaucoup de chapitres !

firm1 commented 10 years ago

Après analyse, le problème viendrait de zmarkdown et plus précisément de l'extension smartLegend

cgabard commented 10 years ago

Ça m'ettonait que cette extension, un truc 100% bricolage, n'avait encore rien cassé. Je vais mettre au propre ça, mais en le mettant directement dans les sources et pas sous formes d'extensions du coup.

cgabard commented 10 years ago

@firm1 : qu'est ce qui te fait dire que c'est cette extension ? Tu aurais une back trace a me donner sur ce prob ?

firm1 commented 10 years ago

La backtrace se trouve ici : http://preprod.zestedesavoir.com/tutoriels/off/48/introduction-a-la-vision-par-ordinateur/notions-de-base/quest-ce-quune-image/?version=228388afd407f9ef28e7e81d60dfd0a4437dd618

Et selon ce que je vois, c'est un morceau qui se trouve a l'interieur des balises code qu'il essaye de parser.

Si tu veux tout le texte markdown precis qui le fait cracher pour faire ton test je peux te le filer (quand je chope mon pc)

Alex-D commented 10 years ago

Est-ce que, si ce bug provient de zmarkdown, il ne serait pas judicieux de le reporter sur son dépôt et fermer cette issue ?

Coy0te commented 10 years ago

A priori, le dernier fix a bien fonctionné. Dans mon tuto j'ai l'impression que tout ce qui foirait avant fonctionne désormais.

cgabard commented 10 years ago

Bon puisque le prob semble réglé, je ferme cette f**\ issue tant que d'autres probs se present.