首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C中将RGB转换为RGBA

在C中将RGB转换为RGBA
EN

Stack Overflow用户
提问于 2011-08-16 02:38:08
回答 5查看 8.8K关注 0票数 5

我需要将以RGB字节顺序表示图像的字节数组的内容复制到另一个RGBA(每像素4字节)缓冲区中。alpha通道将在稍后填充。实现这一目标的最快方法是什么?

EN

回答 5

Stack Overflow用户

发布于 2011-08-16 02:56:07

你想要多复杂?您可以将其设置为一次复制一个4字节的字,这在某些32位系统上可能会更快一些:

代码语言:javascript
复制
void fast_unpack(char* rgba, const char* rgb, const int count) {
    if(count==0)
        return;
    for(int i=count; --i; rgba+=4, rgb+=3) {
        *(uint32_t*)(void*)rgba = *(const uint32_t*)(const void*)rgb;
    }
    for(int j=0; j<3; ++j) {
        rgba[j] = rgb[j];
    }
}

最后的额外情况是处理rgb数组缺少一个字节的事实。您还可以使用对齐的移动和SSE指令,一次以4像素的倍数工作,从而使其速度更快。如果你觉得自己真的很有野心,你可以尝试更可怕的模糊操作,比如将缓存线预取到FP寄存器中,然后一次将其传送到另一个映像。当然,您从这些优化中获得的里程将高度依赖于您要针对的特定系统配置,我真的很怀疑这样做是否会有任何好处,而不是简单的事情。

我的简单实验证实,这确实要快一点,至少在我的x86机器上是这样。这是一个基准测试:

代码语言:javascript
复制
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>

void fast_unpack(char* rgba, const char* rgb, const int count) {
    if(count==0)
        return;
    for(int i=count; --i; rgba+=4, rgb+=3) {
        *(uint32_t*)(void*)rgba = *(const uint32_t*)(const void*)rgb;
    }
    for(int j=0; j<3; ++j) {
        rgba[j] = rgb[j];
    }
}

void simple_unpack(char* rgba, const char* rgb, const int count) {
    for(int i=0; i<count; ++i) {
        for(int j=0; j<3; ++j) {
            rgba[j] = rgb[j];
        }
        rgba += 4;
        rgb  += 3;
    }
}

int main() {
    const int count = 512*512;
    const int N = 10000;

    char* src = (char*)malloc(count * 3);
    char* dst = (char*)malloc(count * 4);

    clock_t c0, c1;    
    double t;
    printf("Image size = %d bytes\n", count);
    printf("Number of iterations = %d\n", N);

    printf("Testing simple unpack....");
    c0 = clock();
    for(int i=0; i<N; ++i) {
        simple_unpack(dst, src, count);
    }
    c1 = clock();
    printf("Done\n");
    t = (double)(c1 - c0) / (double)CLOCKS_PER_SEC;
    printf("Elapsed time: %lf\nAverage time: %lf\n", t, t/N);


    printf("Testing tricky unpack....");
    c0 = clock();
    for(int i=0; i<N; ++i) {
        fast_unpack(dst, src, count);
    }
    c1 = clock();
    printf("Done\n");
    t = (double)(c1 - c0) / (double)CLOCKS_PER_SEC;
    printf("Elapsed time: %lf\nAverage time: %lf\n", t, t/N);

    return 0;
}

下面是结果(用g++ -O3编译):

图像大小= 262144字节

迭代次数= 10000

测试简单unpack....Done

运行时间: 3.830000

平均时间: 0.000383

测试棘手的unpack....Done

运行时间: 2.390000

平均时间: 0.000239

所以,在天气好的时候,可能会快40%。

票数 5
EN

Stack Overflow用户

发布于 2011-08-16 02:42:20

最快的方法是使用一个为你实现转换的库,而不是自己编写。您的目标是哪些平台?

如果你出于某种原因坚持自己写,那就先写一个简单而正确的版本。使用它。如果性能不足,您可以考虑对其进行优化。通常,这种类型的转换最好使用向量置换来完成,但确切的最佳序列因目标架构而异。

票数 4
EN

Stack Overflow用户

发布于 2011-08-16 02:43:06

代码语言:javascript
复制
struct rgb {
   char r;
   char g;
   char b;
};

struct rgba {
   char r;
   char g;
   char b;
   char a;
}

void convert(struct rgba * dst, const struct rgb * src, size_t num)
{
    size_t i;
    for (i=0; i<num; i++) {
        dst[i].r = src[i].r;
        dst[i].g = src[i].g;
        dst[i].b = src[i].b;
    }
}

这将是更简洁的解决方案,但正如您提到的字节数组一样,您应该使用以下代码:

代码语言:javascript
复制
// num is still the size in pixels. So dst should have space for 4*num bytes,
// while src is supposed to be of length 3*num.
void convert(char * dst, const char * src, size_t num)
{
    size_t i;
    for (i=0; i<num; i++) {
        dst[4*i] = src[3*i];
        dst[4*i+1] = src[3*i+1];
        dst[4*i+2] = src[3*i+2];
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7069090

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档