在iOS上如何快速转换RGB24到BGR24?

我使用Accelerate.framework的vImageConvert_RGB888toPlanar8vImageConvert_Planar8toRGB888将RGB24转换为vImageConvert_Planar8toRGB888 ,但是当数据需要转换的时候非常大,比如3M或者4M,那么花费在这个上的时间大约是10ms。 所以有人知道一些足够快的想法吗?我的代码是这样的:

 - (void)transformRGBToBGR:(const UInt8 *)pict{ rgb.data = (void *)pict; vImage_Error error = vImageConvert_RGB888toPlanar8(&rgb,&red,&green,&blue,kvImageNoFlags); if (error != kvImageNoError) { NSLog(@"vImageConvert_RGB888toARGB8888 error"); } error = vImageConvert_Planar8toRGB888(&blue,&green,&red,&bgr,kvImageNoFlags); if (error != kvImageNoError) { NSLog(@"vImagePermuteChannels_ARGB8888 error"); } free((void *)pict); } 

使用RGB888ToPlanar8调用可以分散数据,然后再次收集。 这是非常非常糟糕的。 如果33%的内存开销可以承受,请尝试使用RGBA格式并就地置换B / R字节。

如果你想节省33%的百分比,那么我可能会build议如下。 迭代所有像素,但只读取4个字节的倍数(因为lcm(3,4)是12,即3个dword)。

 uint8_t* src_image; uint8_t* dst_image; uint32_t* src = (uint32_t*)src_image; uint32_t* dst = (uint32_t*)dst_image; uint32_t v1, v2, v3; uint32_t nv1, nv2, nv3; for(int i = 0 ; i < num_pixels / 12 ; i++) { // read 12 bytes v1 = *src++; v2 = *src++; v3 = *src++; // shuffle bits in the pixels // [R1 G1 B1 R2 | G2 B2 R3 G3 | B3 R4 G4 B4] nv1 = // [B1 G1 R1 B2] ((v1 >> 8) & 0xFF) | (v1 & 0x00FF0000) | ((v1 >> 16) & 0xFF) | ((v2 >> 24) & 0xFF); nv2 = // [G2 R2 B3 G3] ... nv3 = // [R3 B4 G4 R4] ... // write 12 bytes *dst++ = nv1; *dst++ = nv2; *dst++ = nv3; } 

NEON内在function可以做得更好。

请参阅ARM网站的链接,了解24位交换是如何完成的。

BGR到RGB可以像这样在原地完成:

 void neon_asm_convert_BGR_TO_RGB(uint8_t* img, 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" ); } 

只需交换通道 – BGRA到RGBA

 - (void)convertBGRAFrame:(const CLPBasicVideoFrame &)bgraFrame toRGBA:(CLPBasicVideoFrame &)rgbaFrame { vImage_Buffer bgraImageBuffer = { .width = bgraFrame.width, .height = bgraFrame.height, .rowBytes = bgraFrame.bytesPerRow, .data = bgraFrame.rawPixelData }; vImage_Buffer rgbaImageBuffer = { .width = rgbaFrame.width, .height = rgbaFrame.height, .rowBytes = rgbaFrame.bytesPerRow, .data = rgbaFrame.rawPixelData }; const uint8_t byteSwapMap[4] = { 2, 1, 0, 3 }; vImage_Error error; error = vImagePermuteChannels_ARGB8888(&bgraImageBuffer, &rgbaImageBuffer, byteSwapMap, kvImageNoFlags); if (error != kvImageNoError) { NSLog(@"%s, vImage error %zd", __PRETTY_FUNCTION__, error); } }