2009-06-25 15 views
35

के लिए पिक्सेल अल्फा मान पुनर्प्राप्त करना मैं वर्तमान में UIImageView में पिक्सेल के अल्फा मान को प्राप्त करने का प्रयास कर रहा हूं। मैंने [UIImageView छवि] से CGImage प्राप्त किया है और इससे एक आरजीबीए बाइट सरणी बनाई है। अल्फा premultiplied है।UIImage

CGImageRef image = uiImage.CGImage; 
NSUInteger width = CGImageGetWidth(image); 
NSUInteger height = CGImageGetHeight(image); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
rawData = malloc(height * width * 4); 
bytesPerPixel = 4; 
bytesPerRow = bytesPerPixel * width; 

NSUInteger bitsPerComponent = 8; 
CGContextRef context = CGBitmapContextCreate(
    rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, 
    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big 
); 
CGColorSpaceRelease(colorSpace); 

CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); 
CGContextRelease(context); 

मैं तो UIImageView से निर्देशांकों का उपयोग कर दिया अल्फ़ा चैनल के लिए सरणी सूचकांक की गणना।

int byteIndex = (bytesPerRow * uiViewPoint.y) + uiViewPoint.x * bytesPerPixel; 
unsigned char alpha = rawData[byteIndex + 3]; 

हालांकि मुझे उम्मीदों की अपेक्षा नहीं है। छवि के पूरी तरह से काले पारदर्शी क्षेत्र के लिए मुझे अल्फा चैनल के लिए शून्य-शून्य मान प्राप्त होते हैं। क्या मुझे UIKit और कोर ग्राफिक्स के बीच समन्वय का अनुवाद करने की आवश्यकता है - i.e: क्या y-axis उलटा हुआ है? या क्या मैंने पूर्ववर्ती अल्फा मूल्यों को गलत समझा है?

अद्यतन:

@Nikolai Ruhe के सुझाव यह करने के लिए महत्वपूर्ण था। मुझे वास्तव में UIKit निर्देशांक और कोर ग्राफिक्स निर्देशांक के बीच अनुवाद करने की आवश्यकता नहीं थी।

CGContextSetBlendMode(context, kCGBlendModeCopy); 
+0

अरे तेबोट - मुझे एहसास है कि इस प्रश्न का उत्तर पहले से ही दिया गया है, लेकिन मैं कुछ दिनों पहले ऐसा कुछ कर रहा था। पूरी छवि को चित्रित करने और फिर बाइट सरणी में अनुक्रमणित करने के बजाय, आपको स्रोत छवि के 1px को 1px में 1px बिटमैप संदर्भ_ में खींचना चाहिए। आप सही पिक्सेल को रखने के लिए CGContextDrawImage में rect पैरामीटर का उपयोग कर सकते हैं, और यह 1000 गुना तेज है :-) –

+0

टिप्पणी के लिए धन्यवाद @ बेन गोटो - मैं केवल एक बार छवि खींचता हूं और फिर उसी बाइट सरणी का उपयोग करता रहता हूं। @ निकोलई रुहे ने एकल पिक्सेल ड्रॉ का भी सुझाव दिया लेकिन कहा कि अगर मुझे छवि को एक से अधिक बार आकर्षित करने की आवश्यकता नहीं है, तो मेरे सरणी दृष्टिकोण तेज होंगे, लेकिन अल्फा को बार-बार देखने की आवश्यकता है। – teabot

+1

इस समस्या का उपयोग करने के बाद बस एक त्वरित अपडेट (बाद में) और इसी तरह की समस्या के लिए यहां एक और प्रश्न: CGContextDrawImage पर रेक्ट पैरामीटर का उपयोग "बाउंडिंग बॉक्स के उपयोगकर्ता स्थान में स्थान और आयाम को नियंत्रित करने के लिए किया जाता है जिसमें छवि को आकर्षित करने के लिए किया जाता है। " इसलिए, यदि आप उस आयत 1x1 आकार में बनाते हैं, तो यह चित्र खींचने से पहले पूरी छवि को 1x1 तक स्केल करेगा। सही पिक्सेल प्राप्त करने के लिए आपको निकोलई के उत्तर में CGContextTranslateCTM का उपयोग करने की आवश्यकता है, और स्केलिंग को रोकने के लिए स्रोत छवि के बराबर आय का आकार छोड़ दें। – roguenet

उत्तर

10

हाँ, CGContexts जबकि UIKit में नीचे अंक उनके y- अक्ष ओर इशारा करते हुए है: हालांकि, मिश्रण मोड करने के बाद अपने अल्फा मूल्यों मेरी अपेक्षा कर रहे थे। See the docs। कोड को पढ़ने के बाद

संपादित करें:

:

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

CGContextSetBlendMode(context, kCGBlendModeCopy); 

संपादित करें:

आप देखने कर सकता है बहुत सबसे छोटे संभव CGBitmapContext (1x1 पिक्सेल) का निर्माण करके अधिक कुशल? शायद 8x8? y- अक्ष उलटा: - यानी

CGContextTranslateCTM(context, xOffset, yOffset); 
+0

@ निकोलई रुहे - अच्छी कॉल - मुझे दस्तावेज़ पढ़ना चाहिए था। – teabot

+0

CGImageRef एक स्थिर छवि का प्रतिनिधित्व करता है। एक बार जब मैं बाइट सरणी करता हूं तो मैं CGImage को फेंक देता हूं और फिर अल्फा लुकअप करने के लिए बार-बार बाइट सरणी का उपयोग करता हूं। क्या आपका अनुकूलन इस परिदृश्य में काम करेगा? – teabot

+0

नहीं, बेशक आपको छवि को बार-बार आकर्षित करने की आवश्यकता होगी।मेरा दृष्टिकोण कुछ लुकअप के लिए और अधिक कुशल हो सकता है। यदि आप अपने कोड के साथ बहुत सारे लुकअप स्टिक कर रहे हैं। –

3

मैं UIKit और कोर ग्राफिक्स के बीच समन्वय का अनुवाद करने की जरूरत है: एक कोशिश) और अपने इच्छित स्थान पर संदर्भ के अनुवाद निकालने से पहले है?

यह संभव है। CGImage में, पिक्सेल डेटा अंग्रेजी पढ़ने के क्रम में है: बाएं से दाएं, ऊपर-से-नीचे। तो, सरणी में पहला पिक्सेल शीर्ष-बाएं है; दूसरी पिक्सेल शीर्ष पंक्ति पर बाईं ओर से एक है; आदि

मान लें कि आपके पास यह अधिकार है, आपको यह भी सुनिश्चित करना चाहिए कि आप एक पिक्सेल के भीतर सही घटक को देख रहे हैं। शायद आप आरजीबीए की उम्मीद कर रहे हैं लेकिन एआरजीबी मांग रहे हैं, या इसके विपरीत। या, हो सकता है कि आपके पास बाइट ऑर्डर गलत हो (मुझे नहीं पता कि आईफोन की अंतहीनता क्या है)।

या क्या मैंने पूर्ववर्ती अल्फा मूल्यों को गलत समझा है?

यह ऐसा नहीं लगता है।

उन लोगों के लिए जो नहीं जानते: Premultiplied का मतलब है कि कलर घटकों को अल्फा द्वारा premultiplied हैं; अल्फा घटक वही है चाहे रंग घटकों को इसके द्वारा पूर्ववर्ती किया गया हो या नहीं। आप अल्फा द्वारा रंग घटकों को विभाजित करके इस (अप्रतिबंधित) को उलट सकते हैं।

+0

@ पीटर होसे - यह स्पष्ट करने के लिए धन्यवाद कि कैसे अल्फा काम करता है - मैं अनिश्चित था। – teabot

3

आयताकार बाउंडिंग बॉक्स की बजाय छवि डेटा के अल्फा मान का उपयोग करके स्प्राइट्स के बीच टक्कर के बीच टकराव का पता लगाने के दौरान मुझे यह प्रश्न/उत्तर मिला। संदर्भ एक आईफोन ऐप है ... मैं उपरोक्त सुझाए गए 1 पिक्सेल ड्रा को करने की कोशिश कर रहा हूं और मुझे अभी भी काम करने में समस्याएं आ रही हैं, लेकिन मुझे छवि से डेटा का उपयोग करके CGContextRef बनाने का एक आसान तरीका मिला, और सहायक कार्य यहां:

CGContextRef context = CGBitmapContextCreate(
       rawData, 
       CGImageGetWidth(cgiRef), 
       CGImageGetHeight(cgiRef), 
       CGImageGetBitsPerComponent(cgiRef), 
       CGImageGetBytesPerRow(cgiRef), 
       CGImageGetColorSpace(cgiRef), 
       kCGImageAlphaPremultipliedLast  
    ); 

यह उपरोक्त नमूने में सभी बदसूरत हार्डकोडिंग को छोड़ देता है। CGImageGetBitmapInfo() को कॉल करके अंतिम मान पुनर्प्राप्त किया जा सकता है, लेकिन मेरे मामले में, यह उस छवि से एक मान लौटाता है जिसने ContextCreate फ़ंक्शन में कोई त्रुटि उत्पन्न की है। केवल कुछ संयोजन यहां दस्तावेज के रूप में मान्य हैं: http://developer.apple.com/qa/qa2001/qa1037.html

आशा है कि यह सहायक होगा!

+2

यह सहायक है। बस ध्यान रखें, कि यहां, आपके बाइट्सप्रो रो चौड़ाई * बाइट्सपीरपीक्सल नहीं हो सकते हैं। अनुकूलन के लिए, इसे 16 बाइट सीमाओं तक पहुंचाया जा सकता है। जैसे ही आप rawData को पार करते हैं, यदि आप इसके लिए खाते नहीं हैं, तो आप पैडिंग बाइट्स को पिक्सेल डेटा के रूप में उपयोग कर समाप्त कर देंगे। – mahboudz

+0

इसका यह भी अर्थ है कि आपका कच्चा डेटा जिसे आपने मॉलोक किया है, बिटमैप को पकड़ने के लिए छोटा हो सकता है और वहां एक बफर ओवररन हो सकता है। – mahboudz

+1

मुझे आश्चर्य है कि इसीलिए मुझे आईफोन पर काम करने में परेशानी हो रही है, लेकिन यह सिम्युलेटर पर ठीक काम करता है? http://stackoverflow.com/questions/7506248/alpha-detection-in-layer-ok-on-simulator-not-iphone –

36

यदि आप चाहते हैं कि एक ही बिंदु का अल्फा मान है, तो आपको केवल अल्फा-केवल सिंगल-पॉइंट बफर चाहिए। मेरा मानना ​​है कि यह पर्याप्त होना चाहिए:

// assume im is a UIImage, point is the CGPoint to test 
CGImageRef cgim = im.CGImage; 
unsigned char pixel[1] = {0}; 
CGContextRef context = CGBitmapContextCreate(pixel, 
             1, 1, 8, 1, NULL, 
             kCGImageAlphaOnly); 
CGContextDrawImage(context, CGRectMake(-point.x, 
            -point.y, 
            CGImageGetWidth(cgim), 
            CGImageGetHeight(cgim)), 
       cgim); 
CGContextRelease(context); 
CGFloat alpha = pixel[0]/255.0; 
BOOL transparent = alpha < 0.01; 

UIImage हर बार निर्मित होने की जरूरत नहीं होती है, तो यह बहुत ही कुशल है।

संपादित दिसंबर 8 2011:

एक टिप्पणीकार बताते हैं कि कुछ निश्चित परिस्थितियों में छवि रूप से फ़्लिप किया जा सकता है। मैं इसके बारे में सोच रहा हूं, और मुझे खेद है कि मैंने यूआईएममेज का उपयोग करके कोड नहीं लिखा, इस तरह (मुझे लगता है कि कारण यह है कि उस समय मुझे UIGraphicsPushContext के बारे में नहीं समझा था):

// assume im is a UIImage, point is the CGPoint to test 
unsigned char pixel[1] = {0}; 
CGContextRef context = CGBitmapContextCreate(pixel, 
              1, 1, 8, 1, NULL, 
              kCGImageAlphaOnly); 
UIGraphicsPushContext(context); 
[im drawAtPoint:CGPointMake(-point.x, -point.y)]; 
UIGraphicsPopContext(); 
CGContextRelease(context); 
CGFloat alpha = pixel[0]/255.0; 
BOOL transparent = alpha < 0.01; 

मुझे लगता है कि फ़्लिपिंग समस्या हल हो गई होगी।

+0

मेरे लिए एक आकर्षण की तरह काम करता है! –

+3

किसी कारण से मुझे 'CGContextDrawImage (...': 'CGContextDrawImage (संदर्भ, CGRectMake (-point.x, - (image.size.height-point.y), CGImageGetWidth (cgim) के लिए निम्न पंक्ति का उपयोग करना पड़ा , CGImageGetHeight (cgim)), cgim); ' –

+0

@MattLeff - यदि आपकी छवि फ़्लिप हो जाती है, तो यह सही समझ में आता है, जो आसानी से कोर ग्राफिक्स (जहां y मूल नीचे है) और UIKit के बीच प्रतिबाधा विसंगति के कारण हो सकता है (जहां y मूल शीर्ष पर है) – matt