2012-05-01 16 views
11

किसी दिए गए बिंदु के लिए छवि के पिक्सेल रंग को प्राप्त करने के तरीके के बारे में कई प्रश्न/उत्तर हैं। हालांकि, इन सभी उत्तरों में बड़ी छवियों के लिए वास्तव में धीमी (100-500ms) हैं (उदाहरण के लिए 1000 x 1300 जितनी छोटी है)।आईओएस प्रदर्शन ट्यूनिंग: बड़ी छवियों के लिए पिक्सेल रंग प्राप्त करने का सबसे तेज़ तरीका

वहां अधिकांश कोड नमूने छवि संदर्भ में आकर्षित होते हैं। वे सब के सब समय था जब वास्तविक ड्रॉ जगह लेता ले:

CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage) 

जांच उपकरण में यह पता चलता है कि ड्रॉ स्रोत छवि से डेटा कॉपी करके किया जा रहा है:

enter image description here

मेरे पास है यहां तक ​​कि आंकड़ों को प्राप्त करने के एक अलग माध्यम की भी कोशिश की, उम्मीद है कि बाइट्स को प्राप्त करना वास्तव में अधिक कुशल साबित होगा।

NSInteger pointX = trunc(point.x); 
NSInteger pointY = trunc(point.y); 
CGImageRef cgImage = CGImageCreateWithImageInRect(self.CGImage, 
          CGRectMake(pointX * self.scale, 
             pointY * self.scale, 
             1.0f, 
             1.0f)); 

CGDataProviderRef provider = CGImageGetDataProvider(cgImage); 
CFDataRef data = CGDataProviderCopyData(provider); 

CGImageRelease(cgImage); 

UInt8* buffer = (UInt8*)CFDataGetBytePtr(data); 

CGFloat red = (float)buffer[0]/255.0f; 
CGFloat green = (float)buffer[1]/255.0f; 
CGFloat blue = (float)buffer[2]/255.0f; 
CGFloat alpha = (float)buffer[3]/255.0f; 

CFRelease(data); 

UIColor *pixelColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 

return pixelColor; 

इस विधि यह डेटा पर समय आ गया है लेता कॉपी:

CFDataRef data = CGDataProviderCopyData(provider); 

ऐसा लगता है कि यह बहुत CGImage उदाहरण मैं बनाने रहा हूँ के बजाय, डिस्क से डाटा पढ़ रही है:

enter image description here

अब, कुछ अनौपचारिक परीक्षणों में यह विधि बेहतर प्रदर्शन करती है, लेकिन यह अभी भी उतनी तेज नहीं है जितना मैं चाहता हूं। क्या किसी को अंतर्निहित पिक्सेल डेटा प्राप्त करने का एक तेज़ तरीका पता है ???

उत्तर

1

एक CGImage संदर्भ संभवतः लगभग खाली है और इसमें कोई वास्तविक पिक्सेल डेटा नहीं है जब तक कि आप पहले पिक्सेल को पढ़ने या इसे खींचने का प्रयास न करें, इसलिए किसी छवि से पिक्सल प्राप्त करने की गति तेज करने की कोशिश करने से आपको कहीं भी नहीं मिल सकता है। अभी तक पाने के लिए कुछ भी नहीं है।

क्या आप पीएनजी फ़ाइल से पिक्सल पढ़ने की कोशिश कर रहे हैं? आप फ़ाइल के बाद सीधे जाकर कोशिश कर सकते हैं और पीएनजी प्रारूप को डीकोड कर सकते हैं। भंडारण से डेटा खींचने में अभी भी कुछ समय लगेगा।

+0

छवि को स्क्रीन पर चित्रित किया गया है, मुझे लगता है कि इसका पिक्सेल डेटा पहले ही स्मृति में कहीं है। –

+0

ग्राफिक्स/जीपीयू/डिस्प्ले मेमोरी सीपीयू मेमोरी के समान नहीं है। आप डिस्प्ले की मेमोरी नहीं पढ़ सकते हैं। यह अपारदर्शी और ऐप के सैंडबॉक्स के बाहर है। – hotpaw2

6

तो यह संभव है आप OpenGL ES के माध्यम से स्क्रीन के लिए इस छवि आकर्षित करने के लिए के लिए, आप बनावट कैश कि संस्करण में प्रस्तुत के माध्यम से आईओएस 5.0 में अंतर्निहित पिक्सेल तक बहुत तेज रैंडम एक्सेस मिल सकती है। वे एक OpenGL ES बनावट में संग्रहीत अंतर्निहित BGRA पिक्सेल डेटा (जहां अपनी छवि रह जाएगा) के लिए सीधी स्मृति पहुँच के लिए अनुमति देते हैं, और आप लगभग तुरंत कि बनावट से किसी भी पिक्सेल बाहर ले सकता है।

मैं इसका उपयोग भी बड़े (2048x2048) छवियों के कच्चे पिक्सेल डेटा को पढ़ने के लिए करता हूं, और उन सभी पिक्सल को खींचने के लिए पढ़ने के समय 10-20 एमएस की सीमा में सबसे खराब होते हैं। फिर, एक पिक्सेल में यादृच्छिक पहुंच में लगभग कोई समय नहीं लगता है, क्योंकि आप बस बाइट सरणी में किसी स्थान से पढ़ रहे हैं।

बेशक, इसका मतलब है कि आपको अपनी विशेष छवि को ओपनजीएल ईएस पर पार्स और अपलोड करना होगा, जिसमें कोर ग्राफिक्स के साथ डिस्क और इंटरैक्शन से समान पठन शामिल होगा (यदि आप UIImage के माध्यम से जा रहे हैं) जो आप देखेंगे यदि आपने डिस्क पर एक यादृच्छिक पीएनजी से पिक्सेल डेटा पढ़ने की कोशिश की है, लेकिन ऐसा लगता है कि आपको बस एक बार प्रस्तुत करना होगा और इसे कई बार नमूना देना होगा। यदि ऐसा है, तो ओपनजीएल ईएस और आईओएस 5.0 पर बनावट कैश स्क्रीन पर कुछ भी प्रदर्शित करने के लिए इस पिक्सेल डेटा को पढ़ने के लिए सबसे तेज़ तरीका होगा।

मैं इन प्रक्रियाओं को GPUImage चित्र (छवि अपलोड) और GPUImageRawData (तेज़ कच्चे डेटा का उपयोग) कक्षाओं में अपने ओपन सोर्स GPUImage ढांचे के भीतर encapsulate, यदि आप देखना चाहते हैं कि ऐसा कुछ कैसे काम कर सकता है।

-2
- (BOOL)isWallPixel: (UIImage *)image: (int) x :(int) y { 

CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 
const UInt8* data = CFDataGetBytePtr(pixelData); 

int pixelInfo = ((image.size.width * y) + x) * 4; // The image is png 

//UInt8 red = data[pixelInfo];   // If you need this info, enable it 
//UInt8 green = data[(pixelInfo + 1)]; // If you need this info, enable it 
//UInt8 blue = data[pixelInfo + 2]; // If you need this info, enable it 
UInt8 alpha = data[pixelInfo + 3];  // I need only this info for my maze game 
CFRelease(pixelData); 

//UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f]; // The pixel color info 

if (alpha) return YES; 
else return NO; 
} 
+0

कृपया अपने उत्तर के लिए कुछ और स्पष्टीकरण प्रदान करें। – zachjs

+0

धन्यवाद, मुझे पढ़ने के लिए घोषणा को बदलना था (- (बूल) isWallPixel: (UIImage *) छवि theX: (int) x theY: (int) y {' –

+0

-1: यह बस [इस उत्तर की एक प्रति ] (http://stackoverflow.com/a/7101544/400056) एट्रिब्यूशन के बिना। – DarkDust

4

मुझे अभी तक खींचे गए (फ्रेम बफर में) पिक्सेल तक पहुंचने का कोई तरीका नहीं मिला है। मैंने मापने वाली सबसे तेज़ विधि है:

  1. इंगित करें कि आप इसे बनाते समय kCGImageSourceShouldCache निर्दिष्ट करके छवि को कैश किया जाना चाहते हैं।
  2. (वैकल्पिक) इसे प्रस्तुत करने के लिए मजबूर कर छवि को प्रीकैच करें।
  3. छवि को 1x1 बिटमैप संदर्भ बनाएं।

इस विधि की लागत कैश बिटमैप है, जो तब तक जीवनभर हो सकती है जब तक यह CGImage से जुड़ा हुआ हो। कोड कुछ इस तरह लग रही समाप्त होता है:

  1. डब्ल्यू/ShouldCache झंडा

    NSDictionary *options = @{ (id)kCGImageSourceShouldCache: @(YES) }; 
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); 
    CGImageRef cgimage = CGImageSourceCreateImageAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options); 
    UIImage *image = [UIImage imageWithCGImage:cgimage]; 
    CGImageRelease(cgimage); 
    
  2. Precache छवि

    UIGraphicsBeginImageContext(CGSizeMake(1, 1)); 
    [image drawAtPoint:CGPointZero]; 
    UIGraphicsEndImageContext(); 
    
  3. ड्रा छवि एक 1x1 बिटमैप संदर्भ के लिए छवि बनाएं

    unsigned char pixelData[] = { 0, 0, 0, 0 }; 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
    CGImageRef cgimage = image.CGImage; 
    int imageWidth = CGImageGetWidth(cgimage); 
    int imageHeight = CGImageGetHeight(cgimage); 
    CGContextDrawImage(context, CGRectMake(-testPoint.x, testPoint.y - imageHeight, imageWidth, imageHeight), cgimage); 
    CGColorSpaceRelease(colorSpace); 
    CGContextRelease(context); 
    

पिक्सेलडाटा में आर, जी, बी, और testPoint पर पिक्सेल के ए मान हैं।