【问题标题】:How do I read JPEG and PNG pixels in C++ on Linux?如何在 Linux 上用 C++ 读取 JPEG 和 PNG 像素?
【发布时间】:2010-10-16 04:43:36
【问题描述】:

我正在做一些图像处理,我想单独读取 JPEG 和 PNG 图像中的每个像素值。

在我的部署场景中,使用 3rd 方库对我来说会很尴尬(因为我在目标计算机上的访问受到限制),但我假设没有用于读取 JPEG/PNG 的标准 C 或 C++ 库...

所以,如果您知道使用库的方法,那就太好了,如果不知道,那么仍然欢迎回答!

【问题讨论】:

    标签: c++ c linux png jpeg


    【解决方案1】:

    C 标准中没有标准库来读取文件格式。

    然而,大多数程序,尤其是在 linux 平台上的程序都使用相同的库来解码图像格式:

    对于 jpeg,它是 libjpeg,对于 png,它是 libpng。

    已安装库的可能性非常很高。

    http://www.libpng.org

    http://www.ijg.org

    【讨论】:

      【解决方案2】:

      这是我从 10 年前的源代码中挖掘出来的一个小例程(使用 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;
      }
      

      【讨论】:

      • 您好,要添加哪些头文件以使用 libjpeg 相关功能?
      【解决方案3】:

      对于 jpeg,已经有一个名为 libjpeg 的库,对于 png,还有一个 libpng。好消息是它们可以直接编译,因此目标机器不需要 dll 文件或任何东西。坏消息是它们在 C 中:(

      另外,你自己也别想trying to read the files。如果您想要一种易于阅读的格式,请改用PPM

      【讨论】:

      • 他们在 C 语言中是个坏消息吗?在 C++ 中使用 C 库比在 Perl、Python、Java 或 C# 中使用 C 库要容易得多。而且比尝试使用 C++ 中的任何一个都容易得多。
      • 我曾经不得不用 Java 编写一个 JPEG 解码器来分配一个类。这是一项艰巨的任务(Java 并没有让它变得更容易,让我告诉你),但仍然让我对格式和 Huffman 编码本身有了很多了解。尝试自己做这样的事情肯定是矫枉过正,除非你有非常严格的内存/速度要求,例如在为一个严重受限的嵌入式系统编码时。
      【解决方案4】:

      不幸的是,jpeg 格式是压缩的,因此您必须在读取单个像素之前对其进行解压缩。这是一项不平凡的任务。如果您不能使用某个库,您可能需要参考一个库来了解它是如何解压缩图像的。 sourceforge 上有一个开源库:CImg on sourceforge.

      【讨论】:

        【解决方案5】:

        由于它可以使用曝光,我会提到另一个库来调查:The IM Toolkit,它托管在Sourceforge。它是跨平台的,将文件格式完全从用户那里抽象出来,允许加载和处理图像而无需担心大部分细节。它确实支持开箱即用的 PNG 和 JPEG,并且可以根据需要使用其他导入过滤器进行扩展。

        它还带有大量图像处理运算符...

        它还具有与Lua 的高质量绑定。

        【讨论】:

          【解决方案6】:

          正如 Nils 所指出的,没有用于 JPEG 压缩和图像处理的 C 或 C++ 标准库。

          如果您能够使用第三方库,您可能想尝试GDAL,它支持 JPEG、PNG 和数十种其他格式、压缩和媒体。

          这是一个简单的例子,展示了如何使用 GDAL C++ API 从 JPEG 文件中读取像素数据:

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

          有更完整的GDAL API tutorial 可用。

          【讨论】:

            【解决方案7】:

            我对@9​​87654321@ 库有很好的体验。它支持多种图像格式,并遵循与 OpenGL 非常相似的函数风格。

            当然,它是一个库,但绝对值得一试。

            【讨论】:

              【解决方案8】:

              由于其他答案已经提到您很可能需要使用库,请查看ImageMagick 并查看是否可以执行您需要的操作。它以多种不同的方式与 ImageMagick 的核心功能进行交互,包括适用于几乎所有可用编程语言的库。

              首页:ImageMagick

              【讨论】:

                【解决方案9】:

                如果速度不是问题,您可以尝试LodePNG,它采用非常简约的方式来加载和保存 PNG。

                或者甚至使用来自同一作者的 picoPNG,它是一个函数中的自包含 png 加载器。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2018-05-04
                  • 2018-09-16
                  • 2011-09-20
                  • 2016-06-18
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-22
                  • 1970-01-01
                  相关资源
                  最近更新 更多