2009-03-29 3 views
19

Ich mache eine Bildverarbeitung, und ich möchte jeden Pixelwert in einem JPEG- und PNG-Bild einzeln lesen.Wie lese ich JPEG- und PNG-Pixel in C++ unter Linux?

In meinem Bereitstellungsszenario wäre es für mich schwierig, eine Drittanbieterbibliothek zu verwenden (da ich den Zugriff auf den Zielcomputer eingeschränkt habe), aber ich nehme an, dass es keine Standard C- oder C++ - Bibliothek zum Lesen von JPEG/PNG ...

Also, wenn Sie einen Weg von nicht mit einer Bibliothek dann toll kennen, wenn nicht, dann sind die Antworten immer noch willkommen!

Antwort

19

Im C-Standard gibt es keine Standardbibliothek zum Lesen der Dateiformate.

Allerdings sind die meisten Programme, vor allem auf der Linux-Plattform die gleiche Bibliothek verwenden, um die Bildformate zu entschlüsseln:

Für jpeg es ist libjpeg, für png es libpng ist. Die Wahrscheinlichkeit, dass die Bibliotheken bereits installiert sind, ist sehr hoch.

http://www.libpng.org

http://www.ijg.org

5

Für JPEG, gibt es bereits eine Bibliothek libjpeg genannt, und es ist libpng für png. Die gute Nachricht ist, dass sie direkt kompilieren und so Ziel-Maschinen keine DLL-Dateien oder irgendetwas benötigen. Die schlechte Nachricht ist, sie sind in C :(

Auch denken Sie nicht einmal von trying to readthe files selbst. Wenn Sie ein einfach zu lesenden Format wollen, statt PPM verwenden.

+6

Wie ist es schlechte Nachrichten, dass sie in C sind? Es ist viel einfacher, C-Bibliotheken in C++ als C-Bibliotheken in Perl, Python, Java oder C# zu verwenden. Und viel einfacher als die Verwendung von C++. –

+0

Ich musste einmal für eine Klassenzuordnung einen JPEG-Decoder in Java schreiben. Es war eine mörderische Aufgabe (und Java hat es nicht einfacher gemacht, lass mich dir das sagen), gab mir aber trotzdem eine Menge Einblick in das Format und die Huffman-Kodierung. Der Versuch, so etwas selbst zu machen, ist sicherlich ein Overkill, es sei denn, Sie haben sehr enge Speicher-/Geschwindigkeitsanforderungen, zum Beispiel beim Codieren für ein stark eingeschränktes Embedded-System. –

4

Leider JPEG-Format ist Das ist eine nicht-triviale Aufgabe. Wenn Sie eine Bibliothek nicht verwenden können, sollten Sie sich auf eine beziehen, um zu sehen, wie das Bild dekomprimiert wird Source-Bibliothek auf Sourceforge: CImg on sourceforge.

19

Dies ist eine kleine Routine, die ich aus 10 Jahre alten Quellcode (mit libjpeg) gegraben:

#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; 
} 
+0

hi wat r die Header-Dateien für die Verwendung von libjpeg verwandten Funktionen hinzugefügt werden? – suresh

+0

#include

+0

die Kopfzeile hinzugefügt .. –

1

Ich habe gute Erfahrungen mit der DevIL Bibliothek gemacht. Es unterstützt eine breite Palette von Bildformaten und folgt einem Funktionsstil, der OpenGL sehr ähnlich ist.

Zugegeben, es ist eine Bibliothek, aber es ist definitiv einen Versuch wert.

2

Da es die Belichtung verwenden könnte, erwähne ich eine andere Bibliothek zu untersuchen: The IM Toolkit, die bei Sourceforge gehostet wird. Es ist plattformübergreifend und abstrahiert das Dateiformat vollständig vom Benutzer weg, so dass ein Bild geladen und verarbeitet werden kann, ohne sich um die meisten Details kümmern zu müssen. Es unterstützt standardmäßig PNG und JPEG und kann bei Bedarf mit anderen Importfiltern erweitert werden.

Es kommt mit einer großen Sammlung von Operatoren Verarbeitung Bild als auch ...

Es hat auch eine gute Qualität zu Lua verbindlich.

1

Da die anderen Antworten bereits erwähnen, dass Sie wahrscheinlich eine Bibliothek verwenden müssen, schauen Sie sich ImageMagick an und sehen Sie, ob es möglich ist, zu tun, was Sie tun müssen. Es bietet eine Vielzahl von Möglichkeiten, die Kernfunktionen von ImageMagick zu nutzen, einschließlich Bibliotheken für fast jede verfügbare Programmiersprache.

Homepage: ImageMagick

2

Als Nils zeigte, gibt es so etwas wie ein C oder C++ Standardbibliothek für die JPEG-Kompression und Bildmanipulation nicht.

Falls Sie in der Lage sind, eine Bibliothek eines Drittanbieters zu verwenden, können Sie versuchen, GDAL, die JPEG, PNG und Dutzende von anderen Formaten, Komprimierungen und Medien unterstützt.

ist hier einfaches Beispiel, das zeigt, wie Pixeldaten von JPEG-Datei mit GDAL C++ API zu lesen:

#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; 
} 

Es ist vollständigere GDAL API tutorial zur Verfügung.

1

Wenn die Geschwindigkeit kein Problem ist können Sie versuchen LodePNG, die einen sehr minimalistischen Ansatz zum Laden und Speichern von PNG nehmen.

Oder gehen Sie sogar mit PicoPNG vom selben Autor, der ein in sich geschlossener Png-Lader in einer Funktion ist.