【问题标题】:On iOS how to quickly convert RGB24 to BGR24?在 iOS 上如何快速将 RGB24 转换为 BGR24?
【发布时间】:2012-07-27 08:07:31
【问题描述】:

我使用Accelerate.framework中的vImageConvert_RGB888toPlanar8vImageConvert_Planar8toRGB888将RGB24转换为BGR24,但是当需要转换的数据很大时,比如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);
}

【问题讨论】:

  • 当我看到你的标题时,我立刻想到了Accelerator.framework。但是当你使用它时,我认为在 iOS 上没有更好的方法来做这样的事情。
  • @iGranDav:以 OP 的方式使用此框架并不能保证高速。数据复制太多。请参阅我的回答,有详细的解释和指向 ARM 网站的链接来完成这个确切的任务。
  • @iGranDav 这个 plane8 调用是完全错误的。如果你想交换字节,你应该使用 permute。

标签: ios assembly rgb neon accelerate-framework


【解决方案1】:

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

如果您想节省 33% 的费用,那么我可能会提出以下建议。迭代所有像素,但只读取 4 个字节的倍数(因为 lcm(3,4) 是 12,即 3 个 dwords)。

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 内在函数可以做得更好。

查看此链接from ARM's website 了解如何完成 24 位交换。

BGR-to-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"
     );
}

【讨论】:

  • 太伤心了,在我的测试中,**迭代所有像素,但只读取 4 个字节的倍数(因为 lcm(3,4) 是 12,即 3 个 dwords)** 更多比RGB888ToPlanar8慢,成本是RGB888ToPlanar8的两倍。在我的实验中RGB888ToPlanar8需要10ms,另一个需要20ms。
  • 那就用汇编版吧,C版不是 Accelerate框架的竞争对手
  • 对于移位中的错误,我们深表歉意。 ARM 都是 BE/LE,但默认情况下它通常是 little-endian。而且我的 C 代码绝对是大端的。
  • nv1 = ((v1 &gt;&gt; 16) &amp; 0x0000FF) | (v1 &amp; 0x0000FF00) | ((v1 &lt;&lt; 16) &amp; 0x00FF0000) | ((v2 &lt;&lt; 16) &amp; 0xFF000000); nv2 = ((v1 &gt;&gt; 16) &amp; 0x0000FF00) | (v2 &amp; 0xFF) | (v2 &amp; 0xFF000000)| (v3 &lt;&lt; 16 &amp; 0x00FF0000); nv3 = ((v2 &gt;&gt; 16) &amp; 0x000000FF) | (v3 &gt;&gt; 16 &amp; 0x0000FF00) | (v3 &lt;&lt; 16 &amp; 0xFF000000) | (v3 | 0x00FF0000); 这样的代码不起作用,为什么?输出颜色错误。
  • 我不知道 arm 组件,然后我使用这样的函数:` [self neon_asm_convert_BGR_TO_RGB:(UInt8 *)pict numPixel:videoWidth * videoHeight / 24 ];` 但是颜色不对.
【解决方案2】:

只需交换通道 - 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);
    }
}

【讨论】:

    猜你喜欢
    • 2012-07-26
    • 2011-01-02
    • 2011-10-23
    • 2020-05-26
    • 2011-07-02
    • 2019-04-04
    • 2020-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多