2009-06-25 13 views
7

पर BYTE बफर (0-255) कनवर्ट करें मैं एक BYTE बफर (0 से 255 तक) को एक फ्लोट बफर (0.0 से 1.0 तक) में कैसे परिवर्तित कर सकता हूं? बेशक, दो मानों के बीच संबंध होना चाहिए, उदाहरण के लिए: बाइट बफर में 0 .0.एफ फ्लोट बफर में होगा, बाइट बफर में 128 फ्लोट बफर में 5 एफ होगा, बाइट बफर में 255 होगा 1.f फ्लोट बफरबाइट बफर (0.0-1.0)

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

यह बहुत धीमी गति से चलाता है:

वास्तव में इस कोड है कि मैं है। मेरे एक दोस्त ने मुझे एक रूपांतरण तालिका का उपयोग करने का सुझाव दिया, लेकिन मैं जानना चाहता था कि कोई और मुझे एक और दृष्टिकोण दे सकता है या नहीं।

+1

बस पूर्णता के लिए, बाइट बफर में 128 फ्लोट बफर में .5019607843f होगा, न कि .5f। –

उत्तर

9

चाहे आप एक लुकअप टेबल का उपयोग करना चुनते हैं या नहीं, आपका कोड प्रत्येक लूप पुनरावृत्ति के बहुत सारे काम कर रहा है कि वास्तव में इसकी आवश्यकता नहीं है - कनवर्ट करने की लागत को बढ़ाने और गुणा करने के लिए पर्याप्त संभावना है।

अपने पॉइंटर्स को प्रतिबंधित करें, और पॉइंटर्स जिन्हें आप केवल कॉन्स्ट से पढ़ते हैं। 255 तक विभाजित करने के बजाय 1/255 वें गुणा करें। आंतरिक लूप के प्रत्येक पुनरावृत्ति में पॉइंटर्स की गणना न करें, केवल शुरुआती मानों की गणना करें और उन्हें बढ़ाएं। आंतरिक पाश को कुछ बार अनलोल करें। यदि आपका लक्ष्य इसका समर्थन करता है तो वेक्टर सिमड ऑपरेशंस का उपयोग करें। अधिकतम, कमी और इसके साथ शून्य के साथ तुलना करने की तुलना में वृद्धि और तुलना न करें।

कुछ की तरह

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

एक शुरुआत होगी।

+1

कुछ बहुत अच्छे सुझाव। लेकिन वे एक लुकअप टेबल नहीं हराएंगे। ;-) –

+1

आर्किटेक्चर पर निर्भर करता है। गुणा और कन्वर्ट लोड से सस्ता हो सकता है, खासकर यदि वह अपने आर्किटेक्चर की सिम क्षमताओं (एमएमएक्स, एसएसई, अल्टीवेक या जो कुछ भी) को एक ही निर्देश में पूरे पिक्सेल पर करने के लिए उपयोग कर सकता है। लेकिन यह निर्णय उपरोक्त सभी सुझावों से स्वतंत्र रूप से लिया जा सकता है। – moonshadow

+0

यह वास्तव में गति को बेहतर बनाने के लिए कंपाइलर की नौकरी को आसान बनाने के लिए और अधिक करेगा। पॉइंटर्स को संरेखित करने और सिम को सक्षम करने के अलावा - यह वास्तविक बूस्ट – ima

2

इसके लिए एक स्थिर लुकअप टेबल का उपयोग करें। जब मैंने कंप्यूटर ग्राफिक्स कंपनी में काम किया, तो हमने इस परियोजना के साथ जुड़े हुए हार्ड कोड कोड लुकअप टेबल को समाप्त कर दिया।

1

हां, एक लुकअप तालिका लूप में बहुत से डिवीजन करने से निश्चित रूप से तेज़ है। बस 256 प्रीकंप्यूटेड फ्लोट मानों की एक तालिका जेनरेट करें और उस तालिका को इंडेक्स करने के लिए बाइट मान का उपयोग करें।

तुम भी एक छोटे से सूचकांक अभिकलन को हटाने के द्वारा पाश अनुकूलन कर सकते हैं और सिर्फ आप पता लगाने के लिए क्या अड़चन है की जरूरत है की तरह

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

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

कुछ करना:

  • अगर आप अपने डेटा पुनरावृति 'गलत' दिशा में तालिकाओं, आप लगातार एक कैश मिस मारा। कोई लुकअप कभी भी उस पर जाने में मदद नहीं करेगा।
  • यदि आपका प्रोसेसर स्केलिंग में धीमा होने में धीमा है, तो आप देखकर प्रदर्शन को बढ़ावा दे सकते हैं, बशर्ते लुकअप टेबल इसके कैश फिट बैठे।

एक और टिप:

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

1/255 हर बार की गणना करें। यह नहीं पता कि एक संकलक इसे हटाने के लिए पर्याप्त स्मार्ट होगा या नहीं। इसे एक बार गणना करें और हर बार इसे दोबारा लागू करें। इससे भी बेहतर, इसे स्थिर के रूप में परिभाषित करें।

अजगर कोड byte_to_float उत्पन्न करने के लिए:

+0

कंपाइलर निरंतर फोल्डिंग करते हैं इसलिए यह कोई मुद्दा नहीं है। –

1

देखो-अप तालिका सबसे तेज़ तरीका है कन्वर्ट करने के लिए :) ये रहा है।ज फ़ाइल शामिल करने के लिए:

#!/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() 

और सी ++ कोड रूपांतरण प्राप्त करने के लिए:

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

सरल है ना?

8

मुझे पता है कि यह एक पुराना सवाल है, लेकिन चूंकि किसी ने आईईईई फ्लोट प्रतिनिधित्व का उपयोग करके कोई समाधान नहीं दिया है, यहां एक है।

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

यह से अधिक दोगुनी गति से अपने कंप्यूटर (कोर 2 डुओ सीपीयू) पर एक intfloat करने के लिए रूपांतरण के रूप में है।

यहां उपरोक्त कोड का एक एसएसई 3 संस्करण है जो एक समय में 16 फ्लोट करता है। इसके लिए bytepixel और floatpixel 128-बिट गठबंधन होने के लिए आवश्यक है, और कुल आकार 4 का एक से अधिक होना चाहिए। ध्यान दें कि रूपांतरणों को फ़्लोट करने के लिए अंतर्निहित एसएसई 3 यहां बहुत मदद नहीं करेगा, क्योंकि उन्हें किसी भी अतिरिक्त गुणा की आवश्यकता होगी। मेरा मानना ​​है कि यह निर्देश-वार जाने का सबसे छोटा तरीका है, लेकिन यदि आपका कंपाइलर पर्याप्त चालाक नहीं है तो आप हाथों से चीजों को अनलॉक और शेड्यूल करना चाहेंगे।

/* 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; 
} 

संपादित: (f + c/b) * b बजाय f * b + c का उपयोग करके सटीकता में सुधार।

संपादित करें: एसएसई 3 संस्करण जोड़ें।

+0

अब, एसएसई इंट्रिनिक्स का उपयोग करके यह भी नहीं किया जा सकता है? यह एक सिम कोड के शास्त्रीय उदाहरण की तरह दिखता है। (वही मूल कोड के लिए भी सच था ...) –

+0

हाँ! एसएसई में शफल सुविधाओं को सीमित कर दिया गया है लेकिन वे यहां उपयोगी हो सकते हैं। –

संबंधित मुद्दे