libjpeg库解码jpeg图像输出数据排列问题

上一篇文章我们谈到如何修改libjpeg库来解码内存中的jpeg数据这件事情,也确实做到了这一点,然而紧随其后的就发现了一个很蛋疼的问题。因为libjpeg库输出的图像像素是以r-g-b这样的顺序排列的,而在Windows平台上要去显示内存中的图像数据通常是在内存中创建一个位图对象bitmap,然后将要显示的图像数据拷到其相应的位置中,拷贝完成后显示图像。蛋疼的地方就在于bitmap的像素是以b-g-r这样的顺序排列的,这就要求我们在拷贝数据的时候要逐个像素点进行修改,这样做浪费的时间是跟图像的大小成正比的,在图像稍微大一点的情况下,通过写测试程序痛苦的发现比用OpenCV直接读取硬盘的数据显示还要慢,简直不能忍。而即便是不拿去显示直接保存成BMP格式的图像也会遇到同样的问题。

难道就这样放弃了吗?其实解决的方法是有很多的,对于高富帅而言可以买一个性能超级强悍的CPU来让它计算的快点,做过显卡加速的可以用显卡开很多的线程来消除这个运算时间跟图像大小成正比的问题。然而我们有必要这样做吗?回头想一想libjpeg在这个过程中干了什么,它不过就是把jpeg数据解码出来然后逐个像素放进一块内存里面,放完之后传给我们啊,这个r-g-b或者b-g-r不过就是它放的时候地址偏移量设置的不同而已啊!我们如果能修改掉这部分的代码不就能直接连1ns都不需要浪费就解决这个问题吗?

说干就干,从源码入手,在苍茫的代码之中游魂了快半个钟后发现了jdcolor.c文件中有这么一处

 while (--num_rows >= 0) {
    inptr0 = input_buf[0][input_row];
    inptr1 = input_buf[1][input_row];
    inptr2 = input_buf[2][input_row];
    input_row++;
    outptr = *output_buf++;
    for (col = 0; col < num_cols; col++) {
      y  = GETJSAMPLE(inptr0[col]);
      cb = GETJSAMPLE(inptr1[col]);
      cr = GETJSAMPLE(inptr2[col]);
      /* Range-limiting is essential due to noise introduced by DCT losses,
       * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings.
       */
     /* outptr[RGB_RED]   = range_limit[y + Crrtab[cr]];
      outptr[RGB_GREEN] = range_limit[y +
			      ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
						 SCALEBITS))];
      outptr[RGB_BLUE]  = range_limit[y + Cbbtab[cb]];*/

	  outptr[RGB_BLUE] = range_limit[y + Crrtab[cr]];
	  outptr[RGB_GREEN] = range_limit[y +
		  ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
		  SCALEBITS))];
	  outptr[RGB_RED] = range_limit[y + Cbbtab[cb]];

      outptr += RGB_PIXELSIZE;
    }
  }

可以说是踏破铁鞋无觅处得来全不费工夫,这不正是我们要找的地方吗?!把其中的

outptr[RGB_RED]   = range_limit[y + Crrtab[cr]];
outptr[RGB_GREEN] = range_limit[y + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],SCALEBITS))];
outptr[RGB_BLUE]  = range_limit[y + Cbbtab[cb]]

改为

outptr[RGB_BLUE] = range_limit[y + Crrtab[cr]];
outptr[RGB_GREEN] = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS))];
outptr[RGB_RED] = range_limit[y + Cbbtab[cb]];

编译,完成!

现在libjpeg库解码jpeg图像数据输出的图像像素是以b-g-r顺序排列的啦!

时间: 2024-12-06 04:38:12

libjpeg库解码jpeg图像输出数据排列问题的相关文章

利用libjpeg库解码内存中的jpeg数据

在"VS2013编译libjpeg库"这篇文章中本人介绍了如何在VS中编译libjpeg库并提供了一个应用的范例,而这篇文章将在此基础上,介绍如何用libjpeg库来解码内存中的jpeg数据. 其实这个需求已经不新鲜了,网上也能找到别人提供的一些解决方法,之所以要再次写不过是因为本人觉得那些方法或多或少都有些不对的地方,或者说因为版本的迭代,本来是对的,现在有点问题.当然,本人并没有很费心思的自己去一行一行的看源代码,实现的过程基本是参考这篇文章来做的,所以这里只是提供怎么改,而为什么

【转】VS2013编译libjpeg库

原文地址:http://blog.csdn.net/weixinhum/article/details/42718959 现在,很多图像处理工具和开源库都给出了图像解码的函数接口,然而有时这些接口并不能完全满足我们的需求,比如如果我们想直接去解码内存中的JPEG数据就没有这样的接口. 由于之前做的项目刚刚好设备传过来的图像数据就是JPEG格式的,如果将每帧图像数据都保存成文件然后再借助开源库提供的接口去读入文件会显得很掉价,所以做了一些直接解码内存中JPEG数据的研究.经过对比发现libjpeg

VS2013编译libjpeg库

现在,很多图像处理工具和开源库都给出了图像解码的函数接口,然而有时这些接口并不能完全满足我们的需求,比如如果我们想直接去解码内存中的JPEG数据就没有这样的接口. 由于之前做的项目刚刚好设备传过来的图像数据就是JPEG格式的,如果将每帧图像数据都保存成文件然后再借助开源库提供的接口去读入文件会显得很掉价,所以做了一些直接解码内存中JPEG数据的研究.经过对比发现libjpeg库对JPEG图像的编解码支持甚好,而且相对于OpenCV库,复杂度小很多,是故就决定动手来实现我自己想要的接口. 所谓"巧

CUDA 实现JPEG图像解码为RGB数据

了解JPEG数据格式的人应该easy想到.其对图像以8*8像素块大小进行切割压缩的方法非常好用并行处理的思想来实现.而其实英伟达的CUDA自v5.5開始也提供了JPEG编解码的演示样例.该演示样例存储在CUDA的SDK中,即CUDA的默认安装路径"C:\ProgramData\NVDIA Corporation\CUDA Samples\v7.0\7_CUDALibraries\jpegNPP"(v后面的数字依据版本号的不同会变更)中. 该演示样例将图片数据进行了解码和再编码,因为解码

【原创】Libjpeg 库使用心得(一) JPEG图像DCT系数的获取和访问

[原创]继续我的项目研究,现在采用Libjpeg库函数来进行处理,看了库函数之后发现C语言被这些人用的太牛了,五体投地啊...废话不多说,下面就进入正题. Libjpeg库在网上下载还是挺方便的,这里就不附上来了,当然如果找不到的话,也可以发邮件给我,我的邮箱是[email protected]. 打开库函数会看到有很多很多的文件,里面有两个解决方案,一个是apps,一个是jpeg.apps里面有5个工程,分别是用于压缩,解压,转换,读取JPEG中COM段,写入JPEG中COM段,COM段可以看

ijg库解码超大型jpeg图片

1. ijg库解码超大型jpeg图片(>100M)的时候,如何避免内存溢出. 采用边解码边压缩的策略,每次解码一行或者若干行图片数据,然后对于这些解码的数据,进行DQT(量化处理,过滤掉高频的数据,保持低频的数据), 这样解码完,也压缩完. 2. ijg库提供给我们的压缩接口都非常单一,仅有文件流操作,也就是仅仅只有从文件(图片)中读取,然后保存到文件中,而我们在解码大图片的时候, 一般是希望它能够留在缓存中,所以我们需要对源文件进行数据导向内存中 3. 一般而言,我们在进行图片压缩的时候,往往

Libjpeg压缩和解压缩图像

简介 压缩像素数据可以采用的压缩方案是直接压缩bgr24或者将bgr24图像转换为yv12,然后分平面使用libjpeg进行压缩;转yv12然后压缩理由是yv12数据量比bgr24少一半;那么压缩完之后应该数据量会更小;但具体是不是真的会更好,如果好的话,好了多少,并没有一个定量的测试比对数据;这里我们通过实验数据来进行具体分析以辅助决策如果处理我们的数据. 实验方案 选择25个1600×1200尺寸的图像;随机采样计算压缩后的数据大小和压缩与解压缩的耗时;最后性能比对曲线由两条线构成:一是压缩

你好,C++(5)如何输出数据到屏幕、从屏幕输入数据与读写文件?

2.2  基本输入/输出流 听过HelloWorld.exe的自我介绍之后,大家已经知道了一个C++程序的任务就是描述数据和处理数据.这两大任务的对象都是数据,可现在的问题是,数据不可能无中生有地产生,C++程序也不可能凭空创造出来数据.那么,C++程序中的数据又从何而来呢? 在现实世界中,国与国之间的交流是通过外交官来完成的.在C++世界中,也有负责应用程序跟外界进行数据交流的外交官,它们的名字就是基本输入/输出流对象(iostream).一个C++程序在工作的时候,负责输入的外交官(istr

Response_输出数据,实现文件下载,定时刷新页面,是否缓存,重定向,实现验证码

1.Response_输出数据 1.Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象. ServletResponse -- 通用的response提供了一个响应应该具有最基本的属性和方法|-HttpServletResponse -- 在ServletResponse的基础上针对于HTTP协议增加了很多强化的属性和方法 2.HttpServletResponse对象封装了向客户端发送响应状态码.响应头.实体数