关于如何获得给定点的图像的像素颜色,存在许多问题/答案。但是,对于大型图像(例如,甚至小到1000 x 1300),所有这些答案都真的慢(100-500ms)。
那里的大多数代码示例都绘制到图像上下文。当实际抽签时,所有这些都需要时间:
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage)
在Instruments中对此进行检查后发现,通过从源图像复制数据来完成绘制:
我甚至尝试了另一种获取数据的方法,希望自己获得字节实际上会更有效率。
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
实例:
现在,这种方法,在一些非正式测试中确实表现得更好,但它仍然没有我想要的那么快。 有没有人知道更快获取基础像素数据的方法???
答案 0 :(得分:6)
如果您可以通过OpenGL ES将此图像绘制到屏幕上,则可以通过该版本中引入的纹理缓存快速随机访问iOS 5.0中的基础像素。它们允许直接存储器访问存储在OpenGL ES纹理中的底层BGRA像素数据(图像将驻留在其中),并且您几乎可以立即从该纹理中挑选出任何像素。
我用它来回读偶数大(2048x2048)图像的原始像素数据,读取时间最差的时间在10-20毫秒之间,以拉下所有这些像素。同样,对单个像素的随机访问几乎没有时间,因为您只是从字节数组中的某个位置读取。
当然,这意味着您必须解析并将您的特定图像上传到OpenGL ES,这将涉及从磁盘读取相同内容并与Core Graphics进行交互(如果通过UIImage),您将看到你试图从磁盘上的随机PNG读取像素数据,但听起来你需要渲染一次并从中多次采样。如果是这样的话,OpenGL ES和iOS 5.0上的纹理缓存将是读取屏幕上显示的像素数据的绝对最快方式。
我将这些进程封装在我的开源GPUImage框架内的GPUImagePicture(图像上传)和GPUImageRawData(快速原始数据访问)类中,如果你想看看它是如何工作的那样。
答案 1 :(得分:4)
我还没有找到一种方法来访问绘制的(帧内缓冲区)像素。我测量过的最快的方法是:
此方法的成本是缓存的位图,只要与其关联的CGImage,该位图可能具有生命周期。代码最终看起来像这样:
使用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);
预先图像
UIGraphicsBeginImageContext(CGSizeMake(1, 1));
[image drawAtPoint:CGPointZero];
UIGraphicsEndImageContext();
将图像绘制到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);
pixelData具有testPoint处像素的R,G,B和A值。
答案 2 :(得分:1)
CGImage上下文可能几乎是空的,并且在您尝试读取第一个像素或绘制它之前不包含实际像素数据,因此尝试加速从图像中获取像素可能无法让您随处可见。什么都没有。
您是否尝试从PNG文件中读取像素?您可以尝试直接在文件之后直接进行mmap并自己解码PNG格式。从存储中提取数据仍需要一段时间。
答案 3 :(得分:-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;
}