上一篇文章我们谈到如何修改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顺序排列的啦!
原文:http://blog.csdn.net/weixinhum/article/details/43487333