【问题标题】:libjpeg decoding to BGRlibjpeg 解码为 BGR
【发布时间】:2011-08-02 22:50:39
【问题描述】:

我正在使用 libjpeg 将 jpeg 图像从磁盘解码到分配在堆上的内存缓冲区。我使用jpeg_read_scanlines 从文件中读取和解码每个扫描线。这是完美的工作,将每个像素解码为 24 位 RGB 值。

问题是我正在使用一个额外的第三方库,它需要 BGR 格式(而不是 RGB)的缓冲区。使用这个库时,由于通道的顺序错误,我得到了奇怪的结果。

因此,我想找到一种方法将 libjpeg 解码为 BGR 格式而不是 RGB。我已经浏览了网络,但找不到如何配置 libjpeg 来执行此操作?我知道我可以对内存缓冲区进行额外的传递并手动重新排序颜色通道,但是我正在处理的应用程序对时间非常关键,并且必须尽可能快且尽可能高效。

【问题讨论】:

    标签: c++ image image-processing jpeg libjpeg


    【解决方案1】:

    据我所知,Libjpeg 没有办法做到这一点。
    无论如何,这只是一个 O(n) 的转换。

    【讨论】:

      【解决方案2】:

      为您提供多种解决方案:

      • 按照建议进行转换。如果您处理 4 个像素的组,则可以通过三个 32 位读取和写入、位掩码和移位来完成所有操作,并且速度非常快。
      • 修改 libjpeg 的 YUV 到 RGB 转换或之后的阶段,以便交换 R 和 B。
      • 使用libjpeg-turbo。它向后兼容 libjpeg,具有 SIMD 加速功能,并提供 JCS_EXT_BGRJCS_EXT_BGRX 色彩空间。
      • 修改您的源图像,以便交换它们的 R 和 B 通道。听起来很傻,但它需要零修改源代码。

      另外,您说您追求速度,但您操作的是 BGR 数据(而不是 BGRX)。这对我来说没有多大意义,因为在 32 位边界上对齐像素可能会快得多。

      【讨论】:

      • 非常感谢您提供此解决方案。所以,我切换到 libjpeg-turbo 并将颜色空间 (jpeg_decompress_struct::out_color_space) 设置为 JCS_EXT_BGR。为了进一步优化,我正在考虑迁移到 JCS_EXT_BGRX 并修改我的客户端库以读取 4 字节块,从而获得获取 32 位对齐块而不是重叠 24 位块的好处。我想这会更加缓存友好。
      • 哦,顺便说一句,虽然我们修改输入数据的建议很简洁,但我无法访问这些数据,应该期望它采用标准格式。
      • 很高兴知道它有帮助。请注意,32 位块可能更快的原因并不完全是缓存效率(24 位块占用的空间更少,因此对缓存更好),而是数据访问简单,因为访问具有 24 位像素的随机像素可能需要两个32 位读取(或 3 次 8 位读取),而同样的 32 位像素只需要 1 次 32 位读取。
      • 感谢您的解释,这是有道理的。我想在现代 x86 芯片上获取非 4 字节对齐的 24 位像素会导致两次 32 位读取?一个读取像素的第一个字节,第二个读取像素的第 2 和第 3 个字节(也不必要地获取另外 2 个字节)?
      • 您无法在我知道的任何系统上读取 24 位。要么您读取 32 位并删除您不需要的 8 位,要么您读取 16+8 位,或者您读取 8+8+8 位。如果您读取 32 位并且未对齐,CPU 可能会读取两个 32 位字并为您重新组合它们(以性能为代价),但在某些架构上它可能会崩溃。如果进行多次 8 位读取,性能也会受到影响,这仅仅是因为指令更多。差异可能很小,但具体多少取决于架构。
      【解决方案3】:

      JPEGLIB 说您必须修改 jmorecfg.h 才能更改通常的 R G B 值顺序。 这是文档的链接: http://www.opensource.apple.com/source/tcl/tcl-20/tcl_ext/tkimg/tkimg/libjpeg/libjpeg.doc 它位于数据格式部分

      【讨论】:

        【解决方案4】:

        正如 Antun Tun 所说,配置位于 jmorecfg.h。在我的 libjpeg (v7) 版本中,它位于第 320 行:

        #define RGB_RED     0   /* Offset of Red in an RGB scanline element */
        #define RGB_GREEN   1   /* Offset of Green */
        #define RGB_BLUE    2   /* Offset of Blue */
        

        所以你只需将它们更改为:

        #define RGB_RED     2   /* Offset of Red in an RGB scanline element */
        #define RGB_GREEN   1   /* Offset of Green */
        #define RGB_BLUE    0   /* Offset of Blue */
        

        你就完成了。 cmets进一步说:

        /*
         * RESTRICTIONS:
         * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
         * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not
         *    useful if you are using JPEG color spaces other than YCbCr or grayscale.
         * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
         *    is not 3 (they don't understand about dummy color components!).  So you
         *    can't use color quantization if you change that value.
         */
        

        【讨论】:

          【解决方案5】:

          从libjpeg上一版本开始,也可以修改jpeg_read_header()调用后得到的cinfo对象的out_color_space属性。

          引用libjpeg.txt:

          J_COLOR_SPACE out_color_space

          输出色彩空间。 jpeg_read_header() 基于jpeg_color_space 设置适当的默认值;通常它将是 RGB 或灰度。应用程序可以更改此字段以请求以不同颜色空间输出。例如,将其设置为 JCS_GRAYSCALE 以从颜色文件中获取灰度输出。

          所以,如果你希望你的图像被解码为 BGR,你可以在解压时添加这一行:

          cinfo.out_color_space = JCS_EXT_BGR;
          

          【讨论】:

            【解决方案6】:

            看看我的 JPEG 编解码器。

            我实际上并没有针对 libjpeg 测试它的速度。如果你能做到这一点,那可能是一个启示。 无论如何,解码器都在一个文件中,简单地颠倒通道的顺序将非常简单。

            我在这里维护 JPEG 代码:

            https://github.com/MalcolmMcLean/babyxrc/tree/master/src

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-09-18
              • 2012-01-10
              • 1970-01-01
              • 2012-09-29
              • 2014-03-26
              相关资源
              最近更新 更多