Frage

Wie kann ich einen BYTE-Puffer (von 0 bis 255) mit einem Schwimmer-Puffer (0,0 bis 1,0) zu konvertieren? Natürlich sollte es eine Beziehung zwischen den beiden Werten, zB: 0 in Byte-Puffer in float-Puffer wird .0.f, wird 128 in Byte-Puffer in float Puffer .5f werden, wird 255 in Byte-Puffer werden 1.F in Schwimmer Puffer.

Eigentlich ist dies der Code, den ich habe:

for (int y=0;y<height;y++) {
    for (int x=0;x<width;x++) {
        float* floatpixel = floatbuffer + (y * width + x) * 4;
        BYTE* bytepixel = (bytebuffer + (y * width + x) * 4);
        floatpixel[0] = bytepixel[0]/255.f;
        floatpixel[1] = bytepixel[1]/255.f;
        floatpixel[2] = bytepixel[2]/255.f;
        floatpixel[3] = 1.0f; // A
    }
}

Das läuft sehr langsam. Ein Freund von mir vorgeschlagen, mich eine Umwandlungstabelle zu verwenden, aber ich wollte wissen, ob jemand anderes mir einen anderen Ansatz geben kann.

War es hilfreich?

Lösung

Ob Sie eine Lookup-Tabelle verwenden oder nicht, wird der Code eine Menge Arbeit zu tun jeder Schleifeniterationslatenzzeit, dass es wirklich nicht braucht -. Wahrscheinlich genug, um die Kosten des Konvertiten in den Schatten stellen und sich vermehren

Erklären Sie Ihre Zeiger beschränken und Zeiger Sie nur von const lesen. Multiplizieren mit 1 / 255sten anstelle von 255 des Teilens Sie die Zeiger in jeder Iteration der inneren Schleife nicht berechnen, nur Anfangswerte berechnen und inkrementieren. Ausrollen innere Schleife ein paar Mal. Verwenden Sie Vektor-SIMD-Operationen, wenn Ihr Ziel unterstützt wird. Nicht mit maximal, Abnahme erhöhen und zu vergleichen und zu vergleichen, mit Null statt.

So etwas wie

float* restrict floatpixel = floatbuffer;
BYTE const* restrict bytepixel = bytebuffer;
for( int size = width*height; size > 0; --size )
{
    floatpixel[0] = bytepixel[0]*(1.f/255.f);
    floatpixel[1] = bytepixel[1]*(1.f/255.f);
    floatpixel[2] = bytepixel[2]*(1.f/255.f);
    floatpixel[3] = 1.0f; // A
    floatpixel += 4;
    bytepixel += 4;
}

wäre ein Anfang.

Andere Tipps

Ich weiß, dass dies eine alte Frage, aber da niemand eine Lösung ergab die IEEE Float Darstellung verwendet wird, ist hier ein.

// Use three unions instead of one to avoid pipeline stalls
union { float f; uint32_t i; } t, u, v, w;
t.f = 32768.0f;
float const b = 256.f / 255.f;

for(int size = width * height; size > 0; --size)
{
    u.i = t.i | bytepixel[0]; floatpixel[0] = (u.f - t.f) * b;
    v.i = t.i | bytepixel[1]; floatpixel[1] = (v.f - t.f) * b;
    w.i = t.i | bytepixel[2]; floatpixel[2] = (w.f - t.f) * b;
    floatpixel[3] = 1.0f; // A
    floatpixel += 4;
    bytepixel += 4;
}

Das ist mehr als doppelt so schnell als int float Umwandlung auf meinem Computer (Core 2 Duo CPU).

Hier ist ein SSE3 Version des obigen Code, der 16 Schwimmer in einer Zeit der Fall ist. Es erfordert bytepixel und floatpixel 128-Bit ausgerichtet werden, und die Gesamtgröße ein Vielfaches von 4 Hinweis zu sein, dass die SSE3 Einbau-int zu schweben Conversions werden hier nicht viel helfen, da sie ohnehin eine zusätzliche Multiplikation erfordern. Ich glaube, das ist der kürzeste Weg ist befehlsmäßig zu gehen, aber wenn Ihr Compiler nicht klug genug ist, möchten Sie vielleicht Dinge entrollen und planen von Hand.

/* Magic values */
__m128i zero = _mm_set_epi32(0, 0, 0, 0);
__m128i magic1 = _mm_set_epi32(0xff000000, 0xff000000, 0xff000000, 0xff000000);
__m128i magic2 = _mm_set_epi32(0x47004700, 0x47004700, 0x47004700, 0x47004700);
__m128 magic3 = _mm_set_ps(32768.0f, 32768.0f, 32768.0f, 32768.0f);
__m128 magic4 = _mm_set_ps(256.0f / 255.0f, 256.0f / 255.0f, 256.0f / 255.0f, 256.0f / 255.0f);

for(int size = width * height / 4; size > 0; --size)
{
    /* Load bytes in vector and force alpha value to 255 so that
     * the output will be 1.0f as expected. */
    __m128i in = _mm_load_si128((__m128i *)bytepixel);
    in = _mm_or_si128(in, magic1);

    /* Shuffle bytes into four ints ORed with 32768.0f and cast
     * to float (the cast is free). */
    __m128i tmplo = _mm_unpacklo_epi8(in, zero);
    __m128i tmphi = _mm_unpackhi_epi8(in, zero);
    __m128 in1 = _mm_castsi128_ps(_mm_unpacklo_epi16(tmplo, magic2));
    __m128 in2 = _mm_castsi128_ps(_mm_unpackhi_epi16(tmplo, magic2));
    __m128 in3 = _mm_castsi128_ps(_mm_unpacklo_epi16(tmphi, magic2));
    __m128 in4 = _mm_castsi128_ps(_mm_unpackhi_epi16(tmphi, magic2));

    /* Subtract 32768.0f and multiply by 256.0f/255.0f */
    __m128 out1 = _mm_mul_ps(_mm_sub_ps(in1, magic3), magic4);
    __m128 out2 = _mm_mul_ps(_mm_sub_ps(in2, magic3), magic4);
    __m128 out3 = _mm_mul_ps(_mm_sub_ps(in3, magic3), magic4);
    __m128 out4 = _mm_mul_ps(_mm_sub_ps(in4, magic3), magic4);

    /* Store 16 floats */
    _mm_store_ps(floatpixel, out1);
    _mm_store_ps(floatpixel + 4, out2);
    _mm_store_ps(floatpixel + 8, out3);
    _mm_store_ps(floatpixel + 12, out4);

    floatpixel += 16;
    bytepixel += 16;
}

Bearbeiten :. Verbessert die Genauigkeit von (f + c/b) * b statt f * b + c mit

Bearbeiten . Füge SSE3 Version

Verwenden Sie eine statische Lookup-Tabelle für diese. Wenn ich in einem Computergrafik-Unternehmen arbeitete am Ende haben wir für diese eine hart codierte Lookup-Tabelle mit, die wir mit dem Projekt eingebunden.

Sie müssen herausfinden, was der Engpass ist:

  • , wenn Sie Ihre Datentabellen in der ‚falschen‘ Richtung durchlaufen, treffen Sie immer wieder eine Cache-Miss. Nein Hilfe Lookup wird jemals um das bekommen.
  • , wenn Ihr Prozessor ist langsamer bei der Skalierung als in aufzublicken, können Sie die Leistung steigern durch Nachschlagen, sofern die Lookup-Tabelle paßt es Cache.

Noch ein Tipp:

struct Scale {
    BYTE operator()( const float f ) const { return f * 1./255; }
};
std::transform( float_table, float_table + itssize, floatpixel, Scale() );

Ja, eine Lookup-Tabelle ist auf jeden Fall schneller als in einer Schleife viele Divisionen zu tun. Generieren Sie eine Tabelle mit 256 vorberechneten Float-Werte und verwenden Sie den Byte-Wert zu indizieren, dass Tabellen.

Sie können auch die Schleife ein wenig optimieren, indem die Indexberechnung zu entfernen und nur so etwas wie

float *floatpixel = floatbuffer;
BYTE *bytepixel = bytebuffer;

for (...) {
  *floatpixel++ = float_table[*bytepixel++];
  *floatpixel++ = float_table[*bytepixel++];
  *floatpixel++ = float_table[*bytepixel++];
  *floatpixel++ = 1.0f;
}

Look-up-Tabelle ist der schnellste Weg zu konvertieren :) Hier gehen Sie:

Python-Code zu erzeugen, um die byte_to_float.h Datei enthalten sein:

#!/usr/bin/env python

def main():
    print "static const float byte_to_float[] = {"

    for ii in range(0, 255):
        print "%sf," % (ii/255.0)

    print "1.0f };"    
    return 0

if __name__ == "__main__":
    main()

Und C ++ Code, um die Umwandlung zu erhalten:

floatpixel[0] = byte_to_float[ bytepixel[0] ];

Einfach ist es nicht?

Nicht berechnen 1/255 jedes Mal. Weiß nicht, ob ein Compiler klug genug sein wird, diese zu entfernen. Berechnen Sie es einmal und erneut anwenden, es jedes Mal. Noch besser ist, definieren sie als eine Konstante ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top