Comment lire les pixels JPEG et PNG en C++ sur Linux?

je fais du traitement d'image, et j'aimerais lire individuellement chaque valeur de pixel dans les images JPEG et PNG.

dans mon scénario de déploiement, il serait difficile pour moi d'utiliser une bibliothèque tierce (car j'ai un accès restreint sur l'ordinateur cible), mais je suppose qu'il n'y a pas de bibliothèque c/" class="blnk">C ou C++ standard pour lire JPEG/PNG...

Donc, si vous connaissez un moyen de utiliser une bibliothèque alors très bien, sinon les réponses sont toujours les bienvenues!

21
demandé sur Nick Bolton 2009-03-29 07:55:06

9 réponses

il n'y a pas de bibliothèque standard dans le C-standard pour lire les formats de fichier.

cependant, la plupart des programmes, en particulier sur la plate-forme linux utilisent la même bibliothèque pour décoder les formats d'image:

pour jpeg c'est libjpeg, pour png c'est libpng.

les chances que les fichiers soient déjà installés sont très haute.

http://www.libpng.org

http://www.ijg.org

20
répondu Nils Pipenbrinck 2009-03-29 04:02:39

c'est une petite routine que j'ai creusée à partir d'un code source de 10 ans (en utilisant libjpeg):

#include <jpeglib.h>

int loadJpg(const char* Name) {
  unsigned char a, r, g, b;
  int width, height;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;

  FILE * infile;        /* source file */
  JSAMPARRAY pJpegBuffer;       /* Output row buffer */
  int row_stride;       /* physical row width in output buffer */
  if ((infile = fopen(Name, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", Name);
    return 0;
  }
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  jpeg_stdio_src(&cinfo, infile);
  (void) jpeg_read_header(&cinfo, TRUE);
  (void) jpeg_start_decompress(&cinfo);
  width = cinfo.output_width;
  height = cinfo.output_height;

  unsigned char * pDummy = new unsigned char [width*height*4];
  unsigned char * pTest = pDummy;
  if (!pDummy) {
    printf("NO MEM FOR JPEG CONVERT!\n");
    return 0;
  }
  row_stride = width * cinfo.output_components;
  pJpegBuffer = (*cinfo.mem->alloc_sarray)
    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

  while (cinfo.output_scanline < cinfo.output_height) {
    (void) jpeg_read_scanlines(&cinfo, pJpegBuffer, 1);
    for (int x = 0; x < width; x++) {
      a = 0; // alpha value is not supported on jpg
      r = pJpegBuffer[0][cinfo.output_components * x];
      if (cinfo.output_components > 2) {
        g = pJpegBuffer[0][cinfo.output_components * x + 1];
        b = pJpegBuffer[0][cinfo.output_components * x + 2];
      } else {
        g = r;
        b = r;
      }
      *(pDummy++) = b;
      *(pDummy++) = g;
      *(pDummy++) = r;
      *(pDummy++) = a;
    }
  }
  fclose(infile);
  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  BMap = (int*)pTest; 
  Height = height;
  Width = width;
  Depth = 32;
}
19
répondu Peter Parker 2015-12-03 11:54:29

Pour jpeg, il y a déjà une bibliothèque appelée libjpeg, et n'est libpng pour png. La bonne nouvelle est qu'ils compilent directement et donc les machines cibles n'auront pas besoin de fichiers dll ou quoi que ce soit. La mauvaise nouvelle est qu'ils sont en C : (

ne pensez même pas à essayer de lire les fichiers vous-même. Si vous souhaitez un facile-à-lire, utiliser PPM à la place.

5
répondu rlbond 2009-03-29 04:14:00

malheureusement, le format jpeg est compressé, il faut donc le décompresser avant de lire des pixels individuels. C'est une tâche non triviale. Si vous ne pouvez pas utiliser une bibliothèque, vous pouvez vous référer à un pour voir comment c'est la décompression de l'image. Il existe une bibliothèque libre sur sourceforge:CImg sur le site de sourceforge.

4
répondu Colin 2009-03-29 04:04:35

Puisqu'il pourrait utiliser l'exposition, je mentionnerai une autre bibliothèque pour enquêter: La Boîte à outils de la GI, qui est hébergé à l' Sourceforge. Il s'agit d'une plate-forme croisée, et le format de fichier est complètement abstrait de l'utilisateur, permettant à une image d'être chargée et traitée sans se soucier de la plupart des détails. Il supporte à la fois PNG et JPEG, et peut être étendu avec d'autres filtres d'importation si nécessaire.

Il est livré avec une grande collection des opérateurs de traitement d'image ainsi...

il a aussi une bonne qualité de reliure à Lua.

2
répondu RBerteig 2009-03-29 07:02:16

comme Nils l'a souligné, il n'existe pas de bibliothèque standard C ou C++ pour la compression JPEG et la manipulation d'image.

Dans le cas où vous seriez en mesure d'utiliser une bibliothèque tierce, vous pouvez essayer GDAL qui supporte JPEG, PNG et des dizaines d'autres formats, compressions et médiums.

voici un exemple simple qui montre comment lire les données de pixels à partir du fichier JPEG en utilisant L'API GDAL C++:

#include <gdal_priv.h>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    GDALAllRegister(); // once per application

    // Assume 3-band image with 8-bit per pixel per channel (24-bit depth)
    std::string const file("/home/mloskot/test.jpg");

    // Open file with image data
    GDALDataset* ds = static_cast<GDALDataset*>(GDALOpen(file.c_str(), GA_ReadOnly));
    assert(0 != ds);

    // Example 1 - Read multiple bands at once, assume 8-bit depth per band
    {
        int const ncols = ds->GetRasterXSize();
        int const nrows = ds->GetRasterYSize();
        int const nbands = ds->GetRasterCount();
        int const nbpp = GDALGetDataTypeSize(GDT_Byte) / 8;
        std::vector<unsigned char> data(ncols * nrows * nbands * nbpp);

        CPLErr err = ds->RasterIO(GF_Read, 0, 0, ncols, nrows, &data[0], ncols, nrows, GDT_Byte, nbands, 0, 0, 0, 0);
        assert(CE_None == err);

        // ... use data
    }

    // Example 2 - Read first scanline by scanline of 1 band only, assume 8-bit depth per band
    {
        GDALRasterBand* band1 = ds->GetRasterBand(1);
        assert(0 != band1);

        int const ncols = band1->GetXSize();
        int const nrows = band1->GetYSize();
        int const nbpp = GDALGetDataTypeSize(GDT_Byte) / 8;
        std::vector<unsigned char> scanline(ncols * nbpp);

        for (int i = 0; i < nrows; ++i)
        {
            CPLErr err = band1->RasterIO(GF_Read, 0, 0, ncols, 1, &scanline[0], ncols, 1, GDT_Byte, 0, 0);
            assert(CE_None == err);

            // ... use scanline
        }
    }

    return 0;
}

Il y a plus complet GDAL API tutoriel disponible.

2
répondu mloskot 2010-01-22 13:33:39

j'ai eu de bonnes expériences avec l' diable bibliothèque. Il prend en charge une large gamme de formats d'image et suit un style de fonction très similaire à OpenGL.

certes, c'est une bibliothèque, mais ça vaut vraiment le coup d'essayer.

1
répondu Daniel Sloof 2009-03-29 04:17:34

Depuis les autres réponses déjà mentionner que vous devrez probablement utiliser une bibliothèque, prendre un coup d'oeil à ImageMagick et voir si il est possible de faire ce que vous avez besoin de faire. Il est livré avec une variété de différentes façons d'interfacer avec les fonctionnalités de base D'ImageMagick, y compris des bibliothèques pour presque chaque langage de programmation disponible.

page d'Accueil: ImageMagick

1
répondu X-Istence 2009-03-29 07:05:39

Si la vitesse n'est pas un problème vous pouvez essayer LodePNG qui adoptent une approche très minimaliste du chargement et de l'enregistrement PNG.

ou même aller avec picoPNG du même auteur qui est un chargeur png autonome dans une fonction.

1
répondu Gigi 2010-11-29 18:52:06