2012-05-01 34 views
11

Có một số câu hỏi/câu trả lời về cách để có được những màu điểm ảnh của hình ảnh cho một điểm nhất định. Tuy nhiên, tất cả các câu trả lời là thực sự chậm (100-500ms) cho hình ảnh lớn (thậm chí nhỏ như 1000 x 1300, ví dụ).iOS Performance Tuning: cách nhanh nhất để có được màu pixel camera cho hình ảnh lớn

Hầu hết các mẫu mã ra có vẽ một bối cảnh hình ảnh. Tất cả trong số họ mất nhiều thời gian khi bốc thăm thực tế diễn ra:

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

Kiểm tra này trong Instruments cho thấy rằng hòa đang được thực hiện bằng cách sao chép dữ liệu từ hình ảnh nguồn:

enter image description here

Tôi có thậm chí đã thử một phương tiện khác nhau để lấy dữ liệu, hy vọng rằng việc nhận được các byte sẽ thực sự chứng minh hiệu quả hơn nhiều.

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; 

phương pháp này có đó là thời gian trên các dữ liệu sao chép:

CFDataRef data = CGDataProviderCopyData(provider); 

Nó sẽ xuất hiện mà nó quá là đọc dữ liệu từ đĩa, thay vì CGImage dụ tôi đang tạo ra:

enter image description here

Bây giờ, phương pháp này, trong một số thử nghiệm không chính thức hoạt động tốt hơn, nhưng nó vẫn không nhanh như tôi muốn. Có ai biết cách nhanh hơn để lấy dữ liệu pixel cơ bản không ???

Trả lời

1

Ngữ cảnh CGImage có thể gần như trống và không chứa dữ liệu pixel thực tế cho đến khi bạn cố gắng đọc pixel đầu tiên hoặc vẽ nó, vì vậy việc tăng tốc độ lấy pixel từ hình ảnh có thể không đưa bạn đến bất kỳ đâu. Không có gì để có được.

Bạn đang cố gắng để đọc pixel từ một tập tin PNG? Bạn có thể thử truy cập trực tiếp sau tệp và tự mình định dạng và giải mã định dạng PNG. Nó sẽ vẫn mất một lúc để kéo dữ liệu từ bộ nhớ.

+0

Hình ảnh đã được vẽ trên màn hình, tôi sẽ chỉ ra rằng dữ liệu pixel của nó đã ở đâu đó trong bộ nhớ. –

+0

Bộ nhớ đồ họa/GPU/hiển thị không giống như bộ nhớ CPU. Bạn không thể đọc bộ nhớ của màn hình. Nó mờ đục và bên ngoài sandbox của ứng dụng. – hotpaw2

6

Nếu nó có thể cho bạn để vẽ hình ảnh này lên màn ảnh qua OpenGL ES, bạn có thể nhận được cực nhanh truy cập ngẫu nhiên để các điểm ảnh cơ bản trong iOS 5.0 thông qua bộ nhớ đệm kết cấu giới thiệu trong phiên bản đó. Chúng cho phép để truy cập bộ nhớ trực tiếp đến dữ liệu pixel BGRA cơ bản lưu trữ trong một kết cấu OpenGL ES (nơi hình ảnh của bạn sẽ được cư trú), và bạn có thể chọn ra bất kỳ điểm ảnh từ kết cấu mà gần như ngay lập tức.

Tôi sử dụng tính năng này để đọc lại dữ liệu pixel thô thậm chí còn lớn (2048x2048) và thời gian đọc kém nhất trong khoảng 10-20 ms để kéo tất cả các pixel đó xuống. Một lần nữa, truy cập ngẫu nhiên vào một pixel đơn lẻ hầu như không mất thời gian, bởi vì bạn chỉ đọc từ một vị trí trong một mảng byte. Tất nhiên, điều này có nghĩa là bạn sẽ phải phân tích cú pháp và tải lên hình ảnh cụ thể của bạn lên OpenGL ES, sẽ liên quan đến việc đọc cùng một đĩa và tương tác với Core Graphics (nếu trải qua một UIImage) mà bạn sẽ thấy nếu bạn cố gắng đọc dữ liệu pixel từ một PNG ngẫu nhiên trên đĩa, nhưng có vẻ như bạn chỉ cần render một lần và lấy mẫu từ nó nhiều lần. Nếu vậy, OpenGL ES và bộ đệm kết cấu trên iOS 5.0 sẽ là cách nhanh nhất tuyệt đối để đọc lại dữ liệu pixel này cho một thứ gì đó cũng được hiển thị trên màn hình.

Tôi đóng gói các quy trình này trong các lớp GPUImagePicture (tải lên hình ảnh) và GPUImageRawData (truy cập dữ liệu thô nhanh) trong khuôn khổ mã nguồn mở GPUImage của tôi, nếu bạn muốn xem cách hoạt động của tính năng này.

-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

Vui lòng cung cấp thêm một số giải thích cho câu trả lời của bạn. – zachjs

+0

cảm ơn, tôi đã phải thay đổi khai báo để đọc '(- (BOOL) isWallPixel: (UIImage *) hình ảnh theX: (int) x theY: (int) y {' –

+0

-1: Đây chỉ đơn giản là một bản sao của [câu trả lời này ] (http://stackoverflow.com/a/7101544/400056) không có ghi nhận tác giả. – DarkDust

4

Tôi chưa tìm cách truy cập vào pixel được vẽ (trong bộ đệm khung). Phương pháp nhanh nhất tôi đã đo là:

  1. Cho biết bạn muốn hình ảnh được lưu trong bộ nhớ cache bằng cách chỉ định kCGImageSourceShouldCache khi tạo.
  2. (tùy chọn) Đặt trước hình ảnh bằng cách buộc nó hiển thị.
  3. Vẽ hình ảnh một ngữ cảnh bitmap 1x1.

Chi phí của phương pháp này là bitmap được lưu trong bộ nhớ cache, có thể có suốt đời miễn là CGImage được liên kết với. Mã này kết thúc lên tìm kiếm một cái gì đó như thế này:

  1. Tạo hình ảnh w/ShouldCache cờ

    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 ảnh

    UIGraphicsBeginImageContext(CGSizeMake(1, 1)); 
    [image drawAtPoint:CGPointZero]; 
    UIGraphicsEndImageContext(); 
    
  3. ảnh Draw đến một bối cảnh 1x1 bitmap

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

pixelData có giá trị R, G, B và A của pixel tại điểm kiểm tra.

Các vấn đề liên quan