【问题标题】:How to blend two RGB unsigned byte colors stored as unsigned 32bit ints fast?如何快速混合存储为无符号 32 位整数的两种 RGB 无符号字节颜色?
【发布时间】:2016-12-12 02:49:01
【问题描述】:

给定 2 种 RGB 颜色存储为 32 位整数(8 位 alpha 可以忽略或设置为 0xff)。

使用 0-255 之间的第三个整数混合它们的最快方法是什么。


这是一个简单的实现,它只是将值插入为整数:

int32_t rgb_blend(uint32_t src, uint32_t dst, uint32_t blend) {
    const uint32_t iblend = 255 - blend;
    union {
        uint32_t u32;
        struct { uint8_t
#if defined(__LITTLE_ENDIAN__)
            a, b, g, r;
#else
            r, g, b, a;
#endif
        } u8;
    } out, *s = (const void *)&src, *d = (const void *)&dst;

    out.u8.r = (uint8_t)((((uint32_t)s->u8.r * iblend) + ((uint32_t)d->u8.r * blend)) / 255);
    out.u8.g = (uint8_t)((((uint32_t)s->u8.g * iblend) + ((uint32_t)d->u8.g * blend)) / 255);
    out.u8.b = (uint8_t)((((uint32_t)s->u8.b * iblend) + ((uint32_t)d->u8.b * blend)) / 255);
    out.u8.a = 0xff;
    return out.u32;
}

这不必完全准确,一些舍入偏差以获得一些额外的性能是可以的。 (i / 256) 向下舍入例如,但可以替换为 (((i * 2) + 255) / (2 * 255) 以在 0.5 处舍入,同时仅使用整数运算。


注意事项:

  1. this question 类似,但询问的是 RGB 颜色,而不是 RGBA alpha 混合。
  2. 虽然问题不是特定的架构,但会对常见架构感兴趣 - 例如 AMD-64、ARM-64。

【问题讨论】:

  • 你的目标是什么机器?
  • 你的代码很慢的原因是操作符/很慢。因此,您可以通过x>>8x/256 估计x/255,就像@ideasman42 的答案一样,或者使用x*257/65536((x<<8)+x)>>16,这会给你一个很好的估计x/255.0039

标签: c performance colors


【解决方案1】:

只能使用加、减、乘和位移来混合颜色(无分支或类型转换):

uint32_t rgb_interp(uint32_t src, uint32_t dst, uint32_t t) {
    assert(t <= 255);
    const uint32_t s = 255 - t;
#if defined(__LITTLE_ENDIAN__)
    return (
        (((((src >> 0)  & 0xff) * s +
           ((dst >> 0)  & 0xff) * t) >> 8)) |
        (((((src >> 8)  & 0xff) * s +
           ((dst >> 8)  & 0xff) * t)     )  & ~0xff) |
        (((((src >> 16) & 0xff) * s +
           ((dst >> 16) & 0xff) * t) << 8)  & ~0xffff) |
        0xff000000
    );
#else
    return (
        (((((src >> 24) & 0xff) * s +
           ((dst >> 24) & 0xff) * t) << 16) & ~0xffffff) |
        (((((src >> 16) & 0xff) * s +
           ((dst >> 16) & 0xff) * t) << 8)  & ~0xffff) |
        (((((src >> 8)  & 0xff) * s +
           ((dst >> 8)  & 0xff) * t)     )  & ~0xff) |
        0xff
    );
#endif
}

RGBA版本供参考:

uint32_t rgba_interp(uint32_t src, uint32_t dst, uint32_t t) {
    assert(t <= 255);
    const uint32_t s = 255 - t;
    return (
        (((((src >> 0)  & 0xff) * s +
           ((dst >> 0)  & 0xff) * t) >> 8)) |
        (((((src >> 8)  & 0xff) * s +
           ((dst >> 8)  & 0xff) * t)     )  & ~0xff) |
        (((((src >> 16) & 0xff) * s +
           ((dst >> 16) & 0xff) * t) << 8)  & ~0xffff) |
        (((((src >> 24) & 0xff) * s +
           ((dst >> 24) & 0xff) * t) << 16) & ~0xffffff)
    );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多