2009-12-16 32 views
10

से रंग मान को परिवर्तित करना फ्लोट से बाइट तक रंग मान को परिवर्तित करने का सही तरीका क्या होगा? पहले तो मैंने सोचा था कि b=f*255.0 यह करना चाहिए, लेकिन अब मैं सोच रहा हूँ, कि इस मामले में केवल सटीक 1.0255 में परिवर्तित हो जाएगा, लेकिन 0.9999 पहले से ही 254 हो जाएगा जो शायद नहीं है जो मैं चाहता ...फ्लोट 0..1 से बाइट 0..255

ऐसा लगता है कि b=f*256.0 बेहतर होगा सिवाय इसके कि सटीक 1.0 के मामले में इसे अवांछित मामला होगा।

अंत में मैं इस का उपयोग कर रहा:

#define F2B(f) ((f) >= 1.0 ? 255 : (int)((f)*256.0)) 
+0

आपके प्रश्न का शीर्षक बाइट को तैरता है, लेकिन सवाल का शरीर बाइट को फ्लोट करने के लिए कहता है। आपको किसकी आवश्यकता है? – pavium

+0

अच्छा बिंदु, तय है कि। जैसा कि आप बाकी प्रश्न से देख सकते हैं जैसा कि यह शीर्षक में कहता है - फ्लोट को बाइट में परिवर्तित करें। – inkredibl

+0

बीटीडब्ल्यू, '0.9 999'' 1.0' के करीब है, और निश्चित रूप से '255' में परिवर्तित किया जाना चाहिए। कोई भी समाधान जो ऐसा करने में विफल रहता है वह गलत होगा। – ToolmakerSteve

उत्तर

16

1.0 केवल मामला गलत हो सकता है, तो अलग से उस मामले को संभालने है: इसके अलावा

b = floor(f >= 1.0 ? 255 : f * 256.0) 

, मजबूर लायक हो सकता है कि च सच है 0 < = च < = 1 कारण गलत व्यवहार से बचने के लिए त्रुटियों को गोल करने के लिए (उदाहरण के लिए एफ = 1.0000001)।

f2 = max(0.0, min(1.0, f)) 
b = floor(f2 == 1.0 ? 255 : f2 * 256.0) 

वैकल्पिक सुरक्षित समाधान:

b = (f >= 1.0 ? 255 : (f <= 0.0 ? 0 : (int)floor(f * 256.0))) 

या

b = max(0, min(255, (int)floor(f * 256.0))) 
+1

एकमात्र चीज जो मुझे चिंतित करती है वह यह है कि अब 255 अचानक अन्य सभी की तुलना में एक उच्चतम सीमा है;)। – inkredibl

+8

"समस्या" आधा बंद अंतराल के बजाय बंद अंतराल होने से आता है। दूसरों के मुकाबले एक अंतराल थोड़ा बड़ा होने के बिना इसे ठीक करने का कोई तरीका नहीं है। यह जानकर स्वयं को कंसोल करें कि अंतराल में तैरने का वितरण [0,1] समान नहीं है (वे शून्य के करीब अधिक घनत्व वाले हैं) इसलिए कोई गारंटी नहीं है कि अन्य अंतराल एक ही आकार के हैं। –

+1

255 0.99609375 से मूल्यों को कवर करना चाहिए 1.0 को शामिल किया गया। यह उत्तर अंतराल में 1.0 शामिल करने का सुझाव देता है। वास्तव में यह बहुत सूक्ष्म है। मेरे लिए यह सबसे अच्छा संभव जवाब है। – mouviciel

0

मेरा मानना ​​है कि सही मंजिल (च * 256), नहीं दौर है। यह अंतराल 0..1 बराबर लंबाई के ठीक 256 जोनों को मैप करेगा।

[संपादित करें] और 256 विशेष मामले के रूप में जांचें।

+0

ठीक है, लेकिन फिर 1.0 * 265 = 256 के बारे में क्या? – inkredibl

+0

मंजिल (क्लैंप (एफ, 0, 0.9 99 99 99) * 256) – Martin

+0

@ मार्टिन, बेहतर, हालांकि सुरक्षित होना अभी भी 'f' को क्लैंप करना आवश्यक है, यदि एफ में गोल-ऑफ त्रुटि होने के लिए यह संभव है। तो यह जरूरी नहीं है कि क्या करने की जरूरत है। फिर भी, मुझे सुझाव पसंद है - अगर इनपुट मान मान्य आरए में जाना जाता है तो यह मदद करता है nge। – ToolmakerSteve

5

तरह

b=f*255.999 

कुछ क्यों कोशिश नहीं विशेष मामला f==1 से छुटकारा मिलता है, लेकिन अभी भी 0.999 255 है

+0

सहमत हैं, यह कोड में आसान है लेकिन स्वीकार्य समाधान से कम परिशुद्धता है। – inkredibl

+2

inkredibl: उदाहरणों को खोजने के लिए आपको कठोर दबाव डाला जाएगा जहां अंतर वास्तव में मायने रखता है ... –

1

स्वीकार्य समाधान विफल होने पर फ्लोट की तुलना में विफल हुआ समाधान विफल रहा।

इस कोड को ठीक काम:

float f; 
uint8_t i; 
//byte to float 
f =CLAMP(((float)((i &0x0000ff))) /255.0, 0.0, 1.0); 
//float to byte 
i =((uint8_t)(255.0f *CLAMP(f, 0.0, 1.0))); 

आप क्लैंप नहीं है:

#define CLAMP(value, min, max) (((value) >(max)) ? (max) : (((value) <(min)) ? (min) : (value))) 

या पूर्ण आरजीबी के लिए:

integer_color =((uint8_t)(255.0f *CLAMP(float_color.r, 0.0, 1.0)) <<16) | 
       ((uint8_t)(255.0f *CLAMP(float_color.g, 0.0, 1.0)) <<8) | 
       ((uint8_t)(255.0f *CLAMP(float_color.b, 0.0, 1.0))) & 0xffffff; 

float_color.r =CLAMP(((float)((integer_color &0xff0000) >>16)) /255.0, 0.0, 1.0); 
float_color.g =CLAMP(((float)((integer_color &0x00ff00) >>8)) /255.0, 0.0, 1.0); 
float_color.b =CLAMP(((float)((integer_color &0x0000ff))) /255.0, 0.0, 1.0); 
+2

समझें कि आपके पहले वाक्य से क्या मतलब है ... – inkredibl

+0

स्वीकार्य समाधान के साथ मैं एक संभावित समस्या को देखता हूं, यह सटीक '==' की बजाय '=='; मैंने इसे सही करने के लिए एक संपादन सबमिट कर दिया है (हालांकि संपादन केवल तभी महत्वपूर्ण होता है जब फ्लोट वैल्यू 1.0 से थोड़ा अधिक हो।) इसमें एक न्यूनतम/अधिकतम "सुरक्षित" संस्करण भी शामिल है - क्या आप आरोप लगा रहे हैं कि यह सुरक्षित नहीं है? मैंने अब दो सरल "सुरक्षित" विकल्प जोड़े हैं जो अधिक स्पष्ट रूप से सही हैं। – ToolmakerSteve

+0

नोट: आपका उपयोग '255' आपके उत्तर को कुछ हद तक [मेरे नए उत्तर] (https://stackoverflow.com/a/46575472/199364) के समान बनाता है। हालांकि, '* 255' ** का उपयोग करके ** के बिना **, जैसा कि आप यहां करते हैं, निश्चित रूप से एक गलती है, किसी भी भाषा में ** ** पूर्णांक में कनवर्ट करते समय ** truncates। विशेष रूप से, '(int) (0.999 * 255)' '254' तक छोटा हो जाता है, जो एक खराब विकल्प है: 1.0 के करीब एक मान 255 होना चाहिए। आपके सूत्र में 255 प्राप्त करना लगभग असंभव है, जब तक इनपुट बिल्कुल ठीक न हो 1.0। जबकि मैंने इसका परीक्षण नहीं किया है, मुझे लगता है कि '(uint8_t)' में एक ही छंटनी विशेषता है। – ToolmakerSteve

0
public static void floatToByte(float f) 
{ 
    return (byte)(f * 255 % 256) 
} 

मान < 1 सटीक रूप से परिवर्तित कर रहे हैं।

मानते हैं कि रूपांतरण के बाद 255 और 256 के बीच गिरने पर बाइट में परिवर्तित होने पर 255 तक फर्श लगाया जाता है।

मान> 1 % ऑपरेटर का उपयोग कर 0 पर वापस लूप किए गए हैं।

+5

रंगों के लिए अजीब समाधान। तो सफेद से सफेद काला हो जाता है? – inkredibl

1

मैंने हमेशा round(f * 255.0) किया है।

परीक्षण (1 के लिए विशेष मामला) और/या अन्य उत्तरों में क्लैंपिंग की कोई आवश्यकता नहीं है। चाहे यह आपके उद्देश्यों के लिए एक वांछनीय उत्तर है, इस पर निर्भर करता है कि आपका लक्ष्य इनपुट मानों को जितना संभव हो सके [मेरे सूत्र] से मिलान करना है, या प्रत्येक घटक को 256 बराबर अंतराल [अन्य सूत्र] में विभाजित करना है।

मेरे सूत्र का संभावित नकारात्मक पक्ष यह है कि 0 और 255 अंतराल में केवल अन्य अंतराल की आधा चौड़ाई होती है। उपयोग के वर्षों से, मुझे अभी तक कोई दृश्य सबूत नहीं दिख रहा है कि यह बुरा है। इसके विपरीत, मुझे लगता है कि इनपुट तब तक चरम पर नहीं पहुंचने के लिए बेहतर है - लेकिन यह स्वाद का विषय है।

संभावित उछाल यह है कि [मुझे विश्वास है] रिश्तेदार इनपुट मूल्यों की विस्तृत श्रृंखला के लिए आर-जी-बी घटकों के मूल्य (थोड़ा) अधिक सटीक हैं।
हालांकि मैंने इसे साबित करने की कोशिश नहीं की है, यह मेरी सहज ज्ञान है, यह देखते हुए कि प्रत्येक घटक के लिए मैं निकटतम उपलब्ध पूर्णांक प्राप्त करने के लिए गोल करता हूं। (जैसे मेरा मानना ​​है कि यदि किसी रंग में जी ~ = 2 एक्स आर है, तो यह सूत्र अक्सर उस अनुपात के करीब रहेगा, हालांकि अंतर काफी छोटा है, और कई अन्य रंग हैं जो 256 फॉर्मूला बेहतर काम करता है। तो यह धो सकते हैं।)

अभ्यास में, 256 या 255-आधारित दृष्टिकोण अच्छे परिणाम प्रदान करते हैं।
0.0..1.0 नाव को 0..255 बाइट से परिवर्तित -


एक और तरीका है255 बनाम 256 मूल्यांकन करने के लिए, अन्य दिशा जांच करने के लिए है।

सूत्र 0..255 पूर्णांक मूल्यों धर्मान्तरित समान रूप से सीमा 0.0..1.0 में मूल्यों से स्थान दिया गया है:

f = b/255.0 

इस दिशा में जा रहे हैं, वहाँ कोई सवाल यह है कि के रूप में उपयोग करने के लिए है 255 या 256 : उपर्युक्त सूत्र सूत्र है जो समान रूप से अनुमानित परिणाम उत्पन्न करता है। निरीक्षण करें कि यह 255 का उपयोग करता है।

दो दिशाओं में 255 सूत्रों के बीच संबंधों को समझने के लिए, इस चित्र पर विचार करें, यदि आप केवल 2 बिट्स था, इसलिए पूर्णांक 0..3 मान को मान:

3 दो के लिए बिट्स के प्रयोग आरेख, अनुरूप करने के लिए 8 बिट्स के लिए 255। रूपांतरण ऊपर से नीचे तक, या नीचे से शीर्ष करने के लिए हो सकता है:

0 --|-- 1 --|-- 2 --|-- 3 
0 --|--1/3--|--2/3--|-- 0 
    1/6  1/2  5/6 

| 4 पर्वतमाला के बीच की सीमाओं कर रहे हैं। निरीक्षण करें कि इंटीरियर में, फ्लोट वैल्यू और पूर्णांक मान उनकी श्रेणियों के मध्य बिंदु पर हैं। ध्यान दें कि सभी मूल्यों के बीच अंतर दोनों प्रतिनिधित्वों में स्थिर है।

यदि आप इन आरेखों को समझते हैं, तो आप समझेंगे कि मैं 255-आधारित सूत्रों को 256-आधारित सूत्रों का पक्ष क्यों देता हूं।


दावा: आप / 255.0 का उपयोग करते हैं बाइट से जा रहा फ्लोट करने के लिए है, लेकिन आपको round(f * 255.0) का उपयोग नहीं करते जब नाव से को बाइट, फिर "औसत राउंड ट्रिप" त्रुटि जा रहा में वृद्धि हुई है। विवरण का पालन करें।

यह आसानी से फ्लोट से शुरू करके, बाइट जाने के बाद, फिर वापस तैरने के द्वारा मापा जाता है। एक साधारण विश्लेषण के लिए, 2-बिट "0..3" आरेखों का उपयोग करें।

फ्लोट मानों की एक बड़ी संख्या के साथ शुरू करें, समान रूप से 0.0 से 1.0 तक की दूरी पर। यह राउंड-ट्रिप इन सभी मानों को 4 मानों पर समूहित करेगा।
आरेख में 6 अर्ध-अंतराल-लंबाई सीमाएं हैं:
0..1/6, 1/6..1/3, .., 5/6..1
प्रत्येक श्रेणी के लिए, औसत दौर- यात्रा त्रुटि आधे सीमा है, इसलिए 1/12 (न्यूनतम त्रुटि शून्य है, अधिकतम त्रुटि 1/6 है, समान रूप से वितरित)।
सभी श्रेणियां एक ही त्रुटि देते हैं; 1/12 राउंड ट्रिप के दौरान कुल औसत त्रुटि होती है।

आप के बजाय * 256 या * 255.999 सूत्रों के किसी भी उपयोग करते हैं, राउंड ट्रिप परिणामों की सबसे ही कर रहे हैं, लेकिन कुछ ही आसन्न श्रृंखला के लिए ले जाया जाता है।
किसी अन्य श्रेणी में कोई भी परिवर्तन त्रुटि बढ़ाता है; उदाहरण के लिए यदि पहले एक ही फ्लोट इनपुट के लिए त्रुटि 1/6 की तुलना में थोड़ा कम था, तो आसन्न श्रेणी के केंद्र को थोड़ा सा त्रुटि में और 1/6 से अधिक त्रुटि में लौट आया। जैसे 0.18 इष्टतम सूत्र => बाइट 1 => फ्लोट 1/3 ~ = 0.333, त्रुटि के लिए | 0.33-0.18| = 0.147; त्रुटि 256 फॉर्मूला => बाइट 0 => फ्लोट 0, त्रुटि 0.18 के लिए, जो इष्टतम त्रुटि 0.147 से बढ़ती है।

* 4 का उपयोग / 3 के साथ चित्र। रूपांतरण एक पंक्ति से अगले तक है।
पहली पंक्ति के असमान अंतर को ध्यान दें: 0..3/8, 3/8..5/8, 5/8..1। उन दूरी 3/8, 2/8, 3/8 हैं। नोट करें कि अंतिम पंक्ति की अंतराल सीमाएं पहली पंक्ति से अलग हैं।

0------|--3/8--|--5/8--|------0 
     1/4  1/2  3/4 
=> 0------|-- 1 --|-- 2 --|------3 

=> 0----|---1/3---|---2/3---|----0 
     1/6  1/2  5/6 

इस बढ़ी हुई त्रुटि से बचने का एकमात्र तरीका बाइट से फ्लोट जाने पर कुछ अलग सूत्रों का उपयोग करना है। यदि आप 256 सूत्रों में से एक में दृढ़ता से विश्वास करते हैं, तो मैं इष्टतम व्यस्त सूत्र निर्धारित करने के लिए इसे आपके पास छोड़ दूंगा।
(प्रति बाइट मान, इसे फ्लोट मानों के मध्य बिंदु को वापस करना चाहिए जो कि बाइट मान बन गया है। 0 से 0, और 3 से 1 को छोड़कर या शायद 0 से 1/8, 3 से 7/8! ऊपर दिए गए आरेख में , यह आपको मध्यम रेखा से वापस शीर्ष रेखा तक ले जाना चाहिए।)

लेकिन अब आपको मुश्किल से बचाव की स्थिति होगी कि आपने समान दूरी वाले बाइट मूल्यों को लिया है, और उन्हें गैर-समान दूरी वाली फ्लोट में परिवर्तित कर दिया है मान।

यदि आप पूर्ण 255 के अलावा किसी भी मूल्य का उपयोग करते हैं, तो आप अपने विकल्प हैं 0..255: या तो औसत राउंड-ट्रिप त्रुटि में वृद्धि, या फ्लोट डोमेन में गैर-वर्दी-दूरी वाले मानों में वृद्धि।

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