2009-03-29 31 views
19

Tôi đang thực hiện một số xử lý hình ảnh và tôi muốn đọc riêng từng giá trị pixel trong một hình ảnh JPEG và PNG.Làm cách nào để đọc các pixel JPEG và PNG trong C++ trên Linux?

Trong kịch bản triển khai, tôi sẽ sử dụng thư viện của bên thứ 3 (vì tôi đã hạn chế truy cập trên máy tính đích), nhưng tôi giả định rằng không có thư viện C hoặc C++ chuẩn để đọc JPEG/PNG ...

Vì vậy, nếu bạn biết cách không phải bằng thư viện thì tuyệt vời, nếu không thì câu trả lời vẫn được hoan nghênh!

Trả lời

19

Không có thư viện chuẩn nào trong tiêu chuẩn C để đọc định dạng tệp.

Tuy nhiên, hầu hết các chương trình, đặc biệt là trên nền tảng Linux sử dụng cùng một thư viện để giải mã các hình ảnh định dạng:

Đối jpeg nó libjpeg, cho png nó libpng.

Cơ hội mà libs đã được cài đặt là rất cao.

http://www.libpng.org

http://www.ijg.org

5

Đối jpeg, đã có một thư viện gọi libjpeg, và có libpng cho png. Tin tốt là họ biên dịch ngay và vì vậy các máy mục tiêu sẽ không cần các tệp dll hoặc bất cứ thứ gì. Tin xấu là họ đang có trong C :(

Ngoài ra, thậm chí không nghĩ về trying to readthe files chính mình. Nếu bạn muốn một định dạng dễ đọc, sử dụng PPM để thay thế.

+6

Tin xấu là chúng ở trong C bằng cách nào? Việc sử dụng các thư viện C trong C++ dễ dàng hơn nhiều so với các thư viện C trong Perl, Python, Java hoặc C#. Và dễ dàng hơn nhiều so với cố gắng sử dụng bất kỳ từ C++. –

+0

Tôi đã từng viết một bộ giải mã JPEG trong Java để gán lớp. Đó là một nhiệm vụ giết người (và Java đã không làm cho nó dễ dàng hơn, hãy để tôi nói với bạn rằng), nhưng tuy nhiên đã cho tôi rất nhiều cái nhìn sâu sắc vào định dạng và Huffman mã hóa chính nó. Việc cố gắng làm một việc như vậy chắc chắn là quá mức cần thiết, trừ khi bạn có yêu cầu về bộ nhớ/tốc độ rất chặt chẽ, ví dụ như khi mã hóa cho một hệ thống nhúng bị hạn chế nghiêm trọng. –

4

Thật không may, định dạng jpeg nén, vì vậy bạn sẽ phải giải nén nó trước khi đọc từng pixel riêng lẻ.Đây là một nhiệm vụ không tầm thường.Nếu bạn không thể sử dụng một thư viện, bạn có thể muốn tham khảo một để xem nó giải nén hình ảnh như thế nào. thư viện nguồn trên sourceforge: CImg on sourceforge.

19

Đây là một thói quen nhỏ mà tôi đã đào từ mã nguồn 10 tuổi (sử dụng 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; 
} 
+0

hi wat r các tập tin tiêu đề được thêm vào để sử dụng các chức năng liên quan đến libjpeg? – suresh

+0

#include

+0

đã thêm tiêu đề .. –

1

Tôi đã có trải nghiệm tốt với thư viện DevIL. Nó hỗ trợ một loạt các định dạng hình ảnh và theo một phong cách chức năng rất giống với OpenGL.

Đã cấp, đây là thư viện nhưng nó chắc chắn đáng để thử.

2

Vì nó có thể sử dụng phơi sáng, tôi sẽ đề cập đến một thư viện khác để điều tra: The IM Toolkit, được lưu trữ tại Sourceforge. Nó là nền tảng chéo, và tóm tắt định dạng tệp hoàn toàn khỏi người dùng, cho phép hình ảnh được tải và xử lý mà không phải lo lắng về hầu hết các chi tiết. Nó hỗ trợ cả PNG và JPEG ra khỏi hộp và có thể được mở rộng bằng các bộ lọc nhập khác nếu cần.

Nó đi kèm với một bộ sưu tập lớn của các nhà khai thác xử lý hình ảnh cũng ...

Nó cũng có một chất lượng tốt ràng buộc để Lua.

1

Vì các câu trả lời khác đã đề cập đến việc bạn cần sử dụng thư viện, hãy xem ImageMagick và xem liệu bạn có thể làm những gì bạn cần. Nó đi kèm với một loạt các cách khác nhau để giao tiếp với chức năng cốt lõi của ImageMagick, bao gồm các thư viện cho hầu như mọi ngôn ngữ lập trình đơn có sẵn.

Trang chủ: ImageMagick

2

Như Nils chỉ, không có những điều như một C hoặc thư viện chuẩn C++ cho nén JPEG và xử lý ảnh.

Trong trường hợp bạn có thể sử dụng thư viện của bên thứ ba, bạn có thể muốn thử GDAL hỗ trợ JPEG, PNG và hàng chục định dạng, nén và phương tiện khác.

Dưới đây là ví dụ đơn giản mà trình bày làm thế nào để đọc dữ liệu pixel từ tập tin JPEG sử dụng GDAL C++ API:

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

Có đầy đủ hơn GDAL API tutorial sẵn.

1

Nếu tốc độ không phải là vấn đề bạn có thể thử LodePNG có cách tiếp cận rất tối giản để tải và lưu PNG.

Hoặc thậm chí đi với picoPNG từ cùng một tác giả là trình tải png độc lập trong một hàm.

Các vấn đề liên quan