Convert RGB to RGBA to C

I need to copy the contents of a byte array representing the image in RGB byte order to another RGBA buffer (4 bytes per pixel). Alpha channel will be filled later. What will be the fastest way to achieve this?

+5
source share
5 answers

The fastest of them is to use a library that implements a conversion for you, and not record it yourself. What platform are you targeting?

If you insist on writing it yourself for some reason, first write a simple and correct version. Use this. If performance is poor, you might consider optimizing it. In general, this kind of transformation is best used using vector permutations, but the exact optimal sequence varies depending on the target architecture.

+4
source

How hard is this to do? You can configure it to copy a 4-byte word at a time, which may be slightly faster on some 32-bit systems:

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. :

#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

....

: 3.830000

: 0,000383

....

: 2.390000

: 0,000239

, , 40% .

+4
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;
    }
}

, , , :

// 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

4/3 . RGBA, 3 255 .

+1

, Nehe , - , .

:

void flipIt(void* buffer)                       // Flips The Red And Blue Bytes (256x256)
{
    void* b = buffer;                       // Pointer To The Buffer
    __asm                               // Assembler Code To Follow
    {
        mov ecx, 256*256                    // Set Up A Counter (Dimensions Of Memory Block)
        mov ebx, b                      // Points ebx To Our Data (b)
        label:                          // Label Used For Looping
            mov al,[ebx+0]                  // Loads Value At ebx Into al
            mov ah,[ebx+2]                  // Loads Value At ebx+2 Into ah
            mov [ebx+2],al                  // Stores Value In al At ebx+2
            mov [ebx+0],ah                  // Stores Value In ah At ebx

            add ebx,3                   // Moves Through The Data By 3 Bytes
            dec ecx                     // Decreases Our Loop Counter
            jnz label                   // If Not Zero Jump Back To Label
    }
}

, , , -.

+1

All Articles