[C++] Librairie de lecture de jpeg2000

Librairie de lecture de jpeg2000 [C++] - C++ - Programmation

Marsh Posté le 22-06-2011 à 22:40:09    

Salut,
 
    Je ne suis pas familier avec les librairies C++ (autres que celles fournies de base dans le compilateur).
 
     Je cherche une librairie C++ (je programme sur Windows avec Visual Studio 2008) qui permettent de lire des fichiers jpeg2000 (je souhaite stocker les valeurs de niveaux de gris dans un tableau d'int à deux dimensions de la taille de l'image lue).
 
    Je suis également à la recherche d'une librairie permettant de lire un fichier vidéo mpeg2 et en extraire des images (que je stockerai de nouveau dans un tableau d'int) ainsi que le timecode correspondant.
 
 
 
                                                        Merci d'avance  :)

Reply

Marsh Posté le 22-06-2011 à 22:40:09   

Reply

Marsh Posté le 23-06-2011 à 12:58:41    

C'est sur que c'est très dur de regarder sur Wikipedia US, à Jpeg2000, la section librairies, et de suivre les liens donnés...
Noter que si c'est pour intégrer à un produit commercial, il faudra sans doute passer par une librairie commerciale faite par un éditeur qui s'occupera de la récupération des royalties annuelles à reverser. Les éditeurs de telles librairies les plus connu (ImageGear, LeadTools...) font cela très bien.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-06-2011 à 09:43:50    

Vu que tu as aussi la video, je ferai tout sous opencv.
 
Tu as une API toute simple:
http://opencv.willowgarage.com/doc [...] video.html

Reply

Marsh Posté le 26-06-2011 à 19:18:19    

Salut,
         merci pour vos réponses. Pour la lecture de jpeg2000 j'ai utilisé la librairie Jasper (que j'ai eu pas mal de mal à comprendre au passage).  
   Pour la lecture de mpeg2 (et l'extraction de leurs images) je vais utiliser opencv comme vous le conseillez, en espérant que l'API soit assez claire. J'avais essayé la librairie libmpeg2 quand j'ouvrais le fichier dsw (pour construire la librairie en faisant "générer en tâche de fond" dans Visual Studio 2008) il ne voulait pas m'ouvrir les fichiers dsp ("impossible de charger le projet à cause d'une altération du fichier projet" )...

Reply

Marsh Posté le 29-06-2011 à 22:47:42    

Bon j'ai finalement réussi à utiliser la librairie libmpeg2. J'ai utilisé les fichiers c fournis avec la librairie (en guise de doc) pour implémenter la lecture du fichier mpeg2 et la récupération des images.
Le problème, c'est qu'en regardant par exemple la première frame de la vidéo (en image N&B, après avoir lu la frame) elle donne cette image :
http://img189.imageshack.us/img189/5315/framenum1.png
 
Alors que l'image devrait ressembler à ça (en N&B) :
http://img828.imageshack.us/img828/2145/framenum1correcte.png
 
 
Voilà le bout de code correspondant à la lecture du fichier image (je rappelle que mes classes d'images que je cherche à créer comportent des tableaux deux dimensions de niveaux de gris) :

Code :
  1. // file est le const char* correspondant au nom du fichier
  2.         FILE * mpgfile;
  3. mpgfile = fopen(file, "rb" );
  4. uint8_t buffer[BUFFER_SIZE];
  5. mpeg2dec_t * decoder;
  6. const mpeg2_info_t * info;
  7. mpeg2_state_t state;
  8. size_t size;
  9. // Nombre de frames lues
  10. int framenum = 0;
  11. decoder = mpeg2_init ();
  12. if (decoder == NULL) {
  13.  cout << "Erreur : impossible d'allouer un objet de type mpeg2dec_t" << endl;
  14.  string blabla;
  15.  cin >> blabla;
  16.  exit(0);
  17. }
  18. info = mpeg2_info (decoder);
  19. size = (size_t)-1;
  20. do {
  21.  state = mpeg2_parse (decoder);
  22.  switch (state) {
  23. case STATE_BUFFER:
  24.  size = fread (buffer, 1, BUFFER_SIZE, mpgfile);
  25.  mpeg2_buffer (decoder, buffer, buffer + size);
  26.  break;
  27. case STATE_SEQUENCE:
  28.  mpeg2_convert (decoder, mpeg2convert_rgb24, NULL);
  29.  break;
  30. case STATE_SLICE:
  31. case STATE_END:
  32. case STATE_INVALID_END:
  33.  if (info->display_fbuf) {
  34.   ImageNB frame(info->sequence->width, info->sequence->height,0);
  35.   int compteur = 0;
  36.   for (int i = 0; i < frame.hauteur; i++) {
  37.    for (int j = 0; j < frame.longueur; j++) {
  38.     int rouge, vert, bleu;
  39.     rouge = (int) (info->display_fbuf->buf[0])[compteur];
  40.     compteur++;
  41.     vert = (int) (info->display_fbuf->buf[0])[compteur];
  42.     compteur++;
  43.     bleu = (int) (info->display_fbuf->buf[0])[compteur];
  44.     compteur++;
  45.     frame(i,j) = (int) (0.30*rouge + 0.59*vert + 0.11*bleu);
  46.     if (frame.valMax < frame(i,j)) {
  47.      frame.valMax = frame(i,j);
  48.     }
  49.     if (frame.valMin > frame(i,j)) {
  50.      frame.valMin = frame(i,j);
  51.     }
  52.    }
  53.   }
  54.   framenum++;
  55.                         // J'enregistre la première frame en format ppm (N&B)
  56.   if (framenum == 1) {
  57.    longueur = frame.longueur;
  58.    hauteur = frame.hauteur;
  59.    frame.creerPgm("frame-num1.ppm" );
  60.   }
  61.   cout << "Frame numero " << framenum << endl;
  62.   cout << " timecode : " << (int) info->gop->hours << ":" << (int) info->gop->minutes << ":" << (int) info->gop->seconds << ":" << (int) info->gop->pictures << ":" << (int) info->gop->flags << endl;
  63.   addImage(frame, framenum);
  64.                         // Je m'arrête de lire après 200 frames, car je souhaite pour l'instant tester uniquement la bonne lecture des frames
  65.   if (framenum >= 200) {
  66.    string blabla;
  67.    cin >> blabla;
  68.    exit(0);
  69.   }
  70.  }
  71.  break;
  72. default:
  73.  break;
  74.  }
  75. } while (size);
  76. mpeg2_close (decoder);


 
 
 
Il se peut que ce code soit incorrecte. Ou alors ça pourrait être dû au fait que les images de la vidéo soient entrelacées (alors que libmpeg2 ne peut que décoder sans désentrelacer), mais même dans ce cas l'image ne devrait pas ressembler à celle observée non ? S'il faut coder un désentrelacement je ne vois pas trop comment faire car je ne comprend pas trop la partie des mpeg2_info_t qui est censée contenir les composantes YUV (devenant RGB dans mon cas car je convertis avec mpeg2_convert) (info->display_fbuf->buf[])...
 
Si quelqu'un si connaît en libmpeg2, je lui serais reconnaissant s'il pouvait m'éclairer (la documentation à ce sujet étant assez rare).

Reply

Marsh Posté le 29-06-2011 à 23:22:06    

Bah plutot que l'entrelacement, on dirai qu'il te manque des slices... Mais je ne peux pas t'aider sur cette lib, je ne la connais pas.
Sinon j'insiste sur le fait que opencv est plutot simple, puisqu'il t'offre la possibilité de lire tes jpeg2000 et video mpeg2 avec la meme interface:
 
jpeg2000:

Code :
  1. Mat frame
  2. frame = imread("toto.jp2" );


Video:

Code :
  1. VideoCapture cap("toto.avi" );
  2. if(!cap.isOpened())
  3.         return -1;
  4. Mat frame;
  5. cap >> frame;


 
Et l'affichage:

Code :
  1. imshow(frame);


Message édité par Amonchakai le 29-06-2011 à 23:24:02
Reply

Marsh Posté le 30-06-2011 à 09:34:22    

Le problème c'est que je ne suis pas sûr qu'OpenCV sache récupérer les timecodes associés aux frames (alors que pour libmpeg2 ça semble possible car je vois une structure mpeg2_gop_t (contenant des attributs hours, minutes, seconds, pictures et flags).  
 
Pour OpenCV, si j'utilise ton bout de code je n'aurai que les pixels de l'image (dans la Mat) sans aucune autre information non ?
La partie que j'avais codée pour la lecture vidéo avec OpenCV est comme suit:

Code :
  1. CvCapture* videoCapture = cvCaptureFromFile(file);
  2. hauteur = (int) cvGetCaptureProperty(videoCapture, CV_CAP_PROP_FRAME_HEIGHT);
  3. longueur = (int) cvGetCaptureProperty(videoCapture, CV_CAP_PROP_FRAME_WIDTH);
  4. ips = (int) cvGetCaptureProperty(videoCapture, CV_CAP_PROP_FPS);
  5. // On compte le nombre de frames total
  6. nbFramesTotal = 0;
  7. bool lecture = true;
  8. while (lecture) {
  9. // Récupération d'une frame et construction de l'objet ImageNB correspondant  
  10. if(!cvGrabFrame(videoCapture)){
  11. lecture = false;
  12. break;
  13. }
  14. nbFramesTotal++;
  15. }
  16. videoCapture = cvCaptureFromFile(file);
  17. // Variable qui va stocker la frame actuellement capturée
  18. IplImage* imageFrame = 0;
  19. for (int cle = 1; cle <= 100; cle++) {
  20. // Récupération d'une frame et construction de l'objet ImageNB correspondant  
  21. if(!cvGrabFrame(videoCapture)){
  22. break;
  23. }
  24. imageFrame = cvRetrieveFrame(videoCapture);
  25. ImageNB imageFrameNB(imageFrame);
  26. // Propriétés de la frame
  27. double posMsec   =       cvGetCaptureProperty(videoCapture, CV_CAP_PROP_POS_MSEC);
  28. int posFrames   = (int) cvGetCaptureProperty(videoCapture, CV_CAP_PROP_POS_FRAMES);
  29. double posRatio  =       cvGetCaptureProperty(videoCapture, CV_CAP_PROP_POS_AVI_RATIO);
  30. cout << posMsec << " " << posFrames << " " << posRatio << endl;
  31. // Ajout de l'imageNB à la liste d'échantillons
  32. (*this).addImage(imageFrameNB, cle);
  33. }


 je n'ai trouvé qu'un frame_count (qui me renvoie parfois des résultats bizarres) et sa position en millisecondes, et la recherche sur le net ne donne rien... Il se peut que le timecode puisse être récupéré avec la position en millisecondes (je vois que cette dernière peut avoir une valeur assez élevée pour la première frame d'une de mes vidéos, il ne s'agit donc pas d'un simple repère de durée sur la vidéo (mais sur la vidéo "originale" s'il y a eu découpage) mais je ne suis sûr de rien. De plus, une valeur en millisecondes ne me donnera pas la frame correspondante du timecode. Il me suffirait d'avoir le timecode exacte de la première frame et je pourrais avoir celui de toutes les autres frames.


Message édité par Suzaku13 le 30-06-2011 à 09:44:37
Reply

Marsh Posté le 30-06-2011 à 14:28:55    

Je ne suis pas sur de comprendre quel timecode que tu souhaite...  
 
De ce que je lis la: http://opencv.jp/opencv-2.2_org/cp [...] video.html
La propriété:
- CV_CAP_PROP_POS_FRAMES: Te donne l'index de la prochaine image a decoder ( /!\ peut etre different de la prochaine image a afficher )
- CV_CAP_PROP_POS_MSEC: te donne le time stamp de l'image courante.
- CV_CAP_PROP_FPS: te donne le nombre d'img/sec.
 
Qu'est ce que tu veux avoir sur le "mpeg2_gop_t" le time stamp du debut de GOP ? La durée d'un GOP ?

Reply

Marsh Posté le 30-06-2011 à 15:18:54    

Je souhaite récupérer le timecode de chaque frame, i.e. la donnée heures:minutes:secondes:frame. Le timecode d'une vidéo peut ne pas commencer à 00:00:00:00 (comme sur certaines vidéos sur lesquelles je travaille), donc il me faut un moyen de récupérer le timecode exact de la première frame, après quoi je peux calculer celui des frames suivantes (en connaissant l'IPS). Par exemple, si le timecode de la première frame est 00:00:01:23 et que l'IPS est de 25, alors le timecode de la seconde frame devrait théoriquement être 00:00:01:24 puis pour la troisière 00:00:02:00 puis 00:00:02:01 ...
 
En regardant la valeur renvoyée par CV_CAP_PROP_POS_MSEC, je remarque qu'elle ne vaut pas forcément 0 (ou ne s'en approche pas forcément, par exemple elle peut commencer à 4*10^7) pour la première frame d'une vidéo. J'ai donc essayé de calculer le timecode ainsi :

Code :
  1. double posMsec   =       cvGetCaptureProperty(videoCapture, CV_CAP_PROP_POS_MSEC);
  2.   int heures, minutes, secondes, frame;
  3.   heures = (int) floor(posMsec/3600000.0);     // 3600000 ms = 1h
  4.   posMsec -= heures*3600000.0;
  5.   minutes = (int) floor(posMsec/60000.0);
  6.   posMsec -= minutes*60000.0;
  7.   secondes = (int) floor(posMsec/1000.0);
  8.   posMsec -= secondes*1000.0;
  9.   frame = (int) (posMsec*ips/1000.0);
  10.   Timecode tc(heures, minutes, secondes, frame);


 
Les valeurs de timecodes obtenues me semblent correctes (au moins pas d'heure supérieure à 23  :) ) mais il faudrait que je puisse voir le "vrai" timecode de la vidéo pour voir si ceux que j'ai calculés sont vraiment corrects. En plus il arrive quelquefois (sûrement à cause des arrondis dûs aux divisions et aux floor) d'obtenir un même timecode pour deux frames successives, ce qui n'est normalement pas possible.
 
En même temps c'est assez bricolage ce calcul du timecode, le mieux serait un moyen de l'extraire directement de la vidéo  :jap: . Donc je sais pas...

Reply

Marsh Posté le 01-07-2011 à 17:33:47    

Bon j'ai utilisé un logiciel affichant le timecode de la première frame d'une vidéo et apparemment le timecode calculé dans mon algorithme n'est pas bon  :fou: .
J'ai donc utilisé la librairie ffmpeg pour lire mes fichiers vidéos car j'avais entendu dire qu'elle permettait de récupérer les timecodes.
 
Après avoir de nouveau galéré pour implémenter la lecture des fichiers et la construction des images avec cette nouvelle librairie, comme un con ce n'est qu'après avoir fait çà que je cherche le moyen de récupérer le timecode et... Je ne vois pas comment  :sol: ! En cherchant un peu je ne vois qu'un attribut timecode_frame_start dans la classe AVCodecContext qui ne permet que de définir nous même le timecode de départ lors de l'encodage d'une vidéo (mais qui n'est pas utilisé dans le décodage d'une vidéo) donc ben ça vaut toujours 0 vu que je fais que décoder...
 
Si quelqu'un s'y connaît avec ffmpeg, peut-il me dire comment récupérer soit le start timecode d'une vidéo soit le timecode d'une frame (encore mieux) ?
 
Svp ne me dites pas que ffmpeg ne peut pas lire les timecodes, parce que je me serais alors péter le c*l à coder la même chose dans 3 librairies différentes pour rien  :pt1cable: ...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed