为了适应多平台,也是满足跨平台的要求,有时候必须转换。因为rgb像素在windows上是按照BGRBGR这样的顺序存储的,而在OS X上则是按照RGBRGB存储。所以如果不做转换,必然在某个平台上出现色差。这里主要演示如何在OS X上实现这种转换。
1.第一种方法最为简单也最慢,就是写一个循环,交换R和B的位置。
Uint8 tmpValue = 0; for(int i = 0; i < numOfPixels; i+=3) { tmpValue = pixelBuffer[i]; pixelBuffer[i] = pixelBuffer[i + 2]; pixelBuffer[i + 2] = tmpValue; }
2.第二种相当快了,使用accelerate.framwork,不过一个较大的限制是最低系统版本要求iOS5,所以使用范围受到了限制。但是不考虑兼容性的话性能提升还是很厉害的。
- (void)transformRGBToBGR:(const UInt8 *)pict { rgb.data = (void *)pict; vImage_Error error = vImageConvert_RGB888toPlanar8(&rgb,&red,&green,&blue,kvImageNoFlags); if (error != kvImageNoError) { NSLog(@"vImageConvert_RGB888toPlanar8 error"); } error = vImageConvert_Planar8toRGB888(&blue,&green,&red,&bgr,kvImageNoFlags); if (error != kvImageNoError) { NSLog(@"vImageConvert_Planar8toRGB888 error"); } free((void *)pict); }
这里首先将内存分布为BGR的数据转换为平面数据,需要三个同原始图像一样宽高的缓冲区存储解析出的R/G/B数据,接下来就可以使用vImageConvert_Planar8toRGB888随意重组他们的顺序,当然要合理,如果你胡乱重组排序的,整合出来的图像肯定是不对的。
由于vImageConvert_Planar8toRGB888和vImageConvert_RGB888toPlanar8都是使用neon汇编优化过的,所以速度很快,几乎已经达到极限了。但是仔细观察,可能就会发现,这种方式需要同样大小的较多的额外存储,尤其是这种函数作为核心函数被调用的次数相当高,导致频繁的分配和释放内存,因而造成内存碎片,影响系统系能。因此,这里就引出了终极解决方案。
3.最快的且节能内存的就是这种方法了,即直接使用neon汇编编写,而不是调用第三方的函数来完成。当数据量较大时,频繁的复制和移动数据废除耗时,而这种方案就可以避免这个问题。相比第二种方法,这种方法节约了2ms,你可能会说,看上去并不是很明显。可是当你了解了CPU的主频也就900MHZ时,你就知道提升不小了。
- (void) neon_asm_convert_BGR_TO_RGB:(UInt8 *) img numPixel:(int) numPixels24 { // numPixels is divided by 24 __asm__ volatile( "0: \n" "# load 3 64-bit regs with interleave: \n" "vld3.8 {d0,d1,d2}, [%0] \n" "# swap d0 and d2 - R and B\n" "vswp d0, d2 \n" "# store 3 64-bit regs: \n" "vst3.8 {d0,d1,d2}, [%0]! \n" "subs %1, %1, #1 \n" "bne 0b \n" : : "r"(img), "r"(numPixels24) : "r4", "r5" ); }
第三种解决方案引自http://stackoverflow.com/questions/11683864/on-ios-how-to-quickly-convert-rgb24-to-bgr24