如何从UIImage(Cocoa Touch)或CGImage(Core Graphics)获取像素数据?
我有一个UIImage(cocoa触摸)。 从那里,我很高兴得到一个CGImage或任何你想要的东西。 我想写这个函数:
- (int)getRGBAFromImage:(UIImage *)image atX:(int)xx andY:(int)yy { // [...] // What do I want to read about to help // me fill in this bit, here? // [...] int result = (red << 24) | (green << 16) | (blue << 8) | alpha; return result; }
谢谢!
仅供参考,我将Keremk的回答与我的原始大纲相结合,清理了错别字,将其归纳为返回一系列颜色,并将整个事物编译。 结果如下:
+ (NSArray*)getRGBAsFromImage:(UIImage*)image atX:(int)x andY:(int)y count:(int)count { NSMutableArray *result = [NSMutableArray arrayWithCapacity:count]; // First get the image into your data buffer CGImageRef imageRef = [image CGImage]; NSUInteger width = CGImageGetWidth(imageRef); NSUInteger height = CGImageGetHeight(imageRef); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char)); NSUInteger bytesPerPixel = 4; NSUInteger 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), imageRef); CGContextRelease(context); // Now your rawData contains the image data in the RGBA8888 pixel format. NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel; for (int i = 0 ; i < count ; ++i) { CGFloat alpha = ((CGFloat) rawData[byteIndex + 3] ) / 255.0f; CGFloat red = ((CGFloat) rawData[byteIndex] ) / alpha; CGFloat green = ((CGFloat) rawData[byteIndex + 1] ) / alpha; CGFloat blue = ((CGFloat) rawData[byteIndex + 2] ) / alpha; byteIndex += bytesPerPixel; UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; [result addObject:acolor]; } free(rawData); return result; }
其中一种方法是将图像绘制到位图上下文中,该位图上下文由给定的色彩空间(在本例中为RGB)支持:(请注意,这会将图像数据复制到该缓冲区,所以您可以想要caching它,而不是每次需要获取像素值时都要执行此操作)
看下面的例子:
// First get the image into your data buffer CGImageRef image = [myUIImage CGImage]; NSUInteger width = CGImageGetWidth(image); NSUInteger height = CGImageGetHeight(image); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = malloc(height * width * 4); NSUInteger bytesPerPixel = 4; NSUInteger 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)); CGContextRelease(context); // Now your rawData contains the image data in the RGBA8888 pixel format. int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel; red = rawData[byteIndex]; green = rawData[byteIndex + 1]; blue = rawData[byteIndex + 2]; alpha = rawData[byteIndex + 3];
苹果的技术问答QA1509显示了以下简单的方法:
CFDataRef CopyImagePixels(CGImageRef inImage) { return CGDataProviderCopyData(CGImageGetDataProvider(inImage)); }
使用CFDataGetBytePtr
来获取实际的字节(和各种CGImageGet*
方法来理解如何解释它们)。
这是一个SO 线程 ,其中@Matt通过移动图像将所需像素渲染到1×1上下文中,以便所需像素与上下文中的一个像素alignment。
NSString * path = [[NSBundle mainBundle] pathForResource:@"filename" ofType:@"jpg"]; UIImage * img = [[UIImage alloc]initWithContentsOfFile:path]; CGImageRef image = [img CGImage]; CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image)); const unsigned char * buffer = CFDataGetBytePtr(data);
UIImage是一个包装的字节是CGImage或CIImage
根据UIImage上的Apple参考资料,该对象是不可变的,您无法访问后备字节。 如果用CGImage
(显式或隐式)填充UIImage
,则可以访问CGImage数据,但如果UIImage
由CIImage
支持,则它将返回NULL
,反之亦然。
图像对象不能直接访问其底层图像数据。 不过,您可以检索其他格式的图片数据,以便在您的应用中使用。 具体而言,可以使用cgImage和ciImage属性分别检索与Core Graphics和Core Image兼容的图像版本。 您还可以使用UIImagePNGRepresentation( :)和UIImageJPEGRepresentation( :_ :)函数生成包含PNG或JPEG格式的图像数据的NSData对象。
解决这个问题的常用技巧
如上所述你的select是
- UIImagePNGRepresentation或JPEG
- 确定图像是否有CGImage或CIImage的支持数据,并在那里
如果您希望不是ARGB,PNG或JPEG数据的输出,并且数据尚未由CIImage支持,则这两种方法都不是特别好用的技巧。
我的build议,尝试CIImage
在开发你的项目的时候,你可能更愿意避免使用UIImage,并select其他的东西。 UIImage作为一个Obj-C图像包装器,经常被CGImage支持,我们认为这是理所当然的。 CIImage往往是一个更好的包装格式,因为你可以使用CIContext来获得你想要的格式,而不需要知道它是如何创build的。 在你的情况下,获取位图将是一个调用的问题
– render:toBitmap:rowBytes:bounds:format:colorSpace:
作为一个额外的奖励,你可以通过链接滤镜到图像上来开始对图像进行很好的操作。 这解决了很多图像颠倒或需要旋转/缩放等问题。
基于Olie和Algal的回答,下面是Swift 3的一个更新的答案
public func getRGBAs(fromImage image: UIImage, x: Int, y: Int, count: Int) -> [UIColor] { var result = [UIColor]() // First get the image into your data buffer guard let cgImage = image.cgImage else { print("CGContext creation failed") return [] } let width = cgImage.width let height = cgImage.height let colorSpace = CGColorSpaceCreateDeviceRGB() let rawdata = calloc(height*width*4, MemoryLayout<CUnsignedChar>.size) let bytesPerPixel = 4 let bytesPerRow = bytesPerPixel * width let bitsPerComponent = 8 let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue guard let context = CGContext(data: rawdata, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { print("CGContext creation failed") return result } context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height)) // Now your rawData contains the image data in the RGBA8888 pixel format. var byteIndex = bytesPerRow * y + bytesPerPixel * x for _ in 0..<count { let alpha = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 3, as: UInt8.self)) / 255.0 let red = CGFloat(rawdata!.load(fromByteOffset: byteIndex, as: UInt8.self)) / alpha let green = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 1, as: UInt8.self)) / alpha let blue = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 2, as: UInt8.self)) / alpha byteIndex += bytesPerPixel let aColor = UIColor(red: red, green: green, blue: blue, alpha: alpha) result.append(aColor) } free(rawdata) return result }
迅速
根据不同的答案,但主要是这个 ,这对我所需要的工作:
UIImage *image1 = ...; // The image from where you want a pixel data int pixelX = ...; // The X coordinate of the pixel you want to retrieve int pixelY = ...; // The Y coordinate of the pixel you want to retrieve uint32_t pixel1; // Where the pixel data is to be stored CGContextRef context1 = CGBitmapContextCreate(&pixel1, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst); CGContextDrawImage(context1, CGRectMake(-pixelX, -pixelY, CGImageGetWidth(image1.CGImage), CGImageGetHeight(image1.CGImage)), image1.CGImage); CGContextRelease(context1);
作为这一行的结果,您将有一个AARRGGBB格式的像素,在4个字节的无符号整数像素1中alpha始终设置为FF。