Iphone 获取图像的像素颜色

Iphone 获取图像的像素颜色,iphone,uiimage,rgb,pixel,Iphone,Uiimage,Rgb,Pixel,如何获取UIImage中特定像素的RGB值?您不能直接访问原始数据,但通过获取此图像的CGImage,您可以访问它。下面是另一个问题的链接,该问题回答了您和您可能遇到的其他有关详细图像处理的问题:请尝试以下非常简单的代码: 我曾经在我的迷宫游戏中检测到一堵墙(我需要的唯一信息是alpha通道,但我包含了代码来为您获取其他颜色): OnTouch -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouc

如何获取UIImage中特定像素的RGB值?

您不能直接访问原始数据,但通过获取此图像的CGImage,您可以访问它。下面是另一个问题的链接,该问题回答了您和您可能遇到的其他有关详细图像处理的问题:

请尝试以下非常简单的代码:

我曾经在我的迷宫游戏中检测到一堵墙(我需要的唯一信息是alpha通道,但我包含了代码来为您获取其他颜色):


OnTouch

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[touches allObjects] objectAtIndex:0];
    CGPoint point1 = [touch locationInView:self.view];
    touch = [[event allTouches] anyObject]; 
    if ([touch view] == imgZoneWheel)
    {
        CGPoint location = [touch locationInView:imgZoneWheel];
        [self getPixelColorAtLocation:location];
        if(alpha==255)
        {
            NSLog(@"In Image Touch view alpha %d",alpha);
            [self translateCurrentTouchPoint:point1.x :point1.y];
            [imgZoneWheel setImage:[UIImage imageNamed:[NSString stringWithFormat:@"blue%d.png",GrndFild]]];
        }
    }
}



- (UIColor*) getPixelColorAtLocation:(CGPoint)point 
{

    UIColor* color = nil;

    CGImageRef inImage;

    inImage = imgZoneWheel.image.CGImage;


    // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue
    CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage];
    if (cgctx == NULL) { return nil; /* error */ }

    size_t w = CGImageGetWidth(inImage);
    size_t h = CGImageGetHeight(inImage);
    CGRect rect = {{0,0},{w,h}};


    // Draw the image to the bitmap context. Once we draw, the memory 
    // allocated for the context for rendering will then contain the 
    // raw image data in the specified color space.
    CGContextDrawImage(cgctx, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap
    // context.
    unsigned char* data = CGBitmapContextGetData (cgctx);
    if (data != NULL) {
        //offset locates the pixel in the data from x,y. 
        //4 for 4 bytes of data per pixel, w is width of one row of data.
        int offset = 4*((w*round(point.y))+round(point.x));
        alpha =  data[offset]; 
        int red = data[offset+1]; 
        int green = data[offset+2]; 
        int blue = data[offset+3]; 
        color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
    }

    // When finished, release the context
    //CGContextRelease(cgctx); 
    // Free image data memory for the context
    if (data) { free(data); }

    return color;
}

- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef)inImage 
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    // Get image width, height. We'll use the entire image.
    size_t pixelsWide = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);

    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.
    colorSpace = CGColorSpaceCreateDeviceRGB();

    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL) 
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits 
    // per component. Regardless of what the source image format is 
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning
    CGColorSpaceRelease( colorSpace );

    return context;
}

首先,创建并附加点击手势识别器允许用户交互:

UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
[self.label addGestureRecognizer:tapRecognizer];
self.label.userInteractionEnabled = YES;
现在执行
-点击手势:

- (void)tapGesture:(UITapGestureRecognizer *)recognizer
{
    CGPoint point = [recognizer locationInView:self.label];

    UIGraphicsBeginImageContext(self.label.bounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self.label.layer renderInContext:context];

    int bpr = CGBitmapContextGetBytesPerRow(context);
    unsigned char * data = CGBitmapContextGetData(context);
    if (data != NULL)
    {
        int offset = bpr*round(point.y) + 4*round(point.x);
        int blue = data[offset+0];
        int green = data[offset+1];
        int red = data[offset+2];
        int alpha =  data[offset+3];

        NSLog(@"%d %d %d %d", alpha, red, green, blue);

        if (alpha == 0)
        {
            // Here is tap out of text
        }
        else
        {
            // Here is tap right into text
        }
    }

    UIGraphicsEndImageContext();
}

这将适用于具有透明背景的UILabel,如果这不是您想要的,您可以将alpha、红色、绿色、蓝色与
self.label.backgroundColor
..

根据Minas Petterson的答案,这里有一种获取UI图像中像素颜色的通用方法:

- (UIColor*)pixelColorInImage:(UIImage*)image atX:(int)x atY:(int)y {

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

    int pixelInfo = ((image.size.width * y) + x ) * 4; // 4 bytes per pixel

    UInt8 red   = data[pixelInfo + 0];
    UInt8 green = data[pixelInfo + 1];
    UInt8 blue  = data[pixelInfo + 2];
    UInt8 alpha = data[pixelInfo + 3];
    CFRelease(pixelData);

    return [UIColor colorWithRed:red  /255.0f
                           green:green/255.0f
                            blue:blue /255.0f
                           alpha:alpha/255.0f];
}

注意,X和Y可以互换;这个函数直接访问底层位图,不考虑可能是UIIMAGE的一部分的旋转。

< P> Minas银行代码中的一些SWIFT代码。最初,我有一些代码来计算像素步长,但我已经更新了答案以使用ComponentLayout。我还将扩展移到了CGImage

- (UIColor *)colorAtPixel:(CGPoint)point inImage:(UIImage *)image {

    if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), point)) {
        return nil;
    }

    // Create a 1x1 pixel byte array and bitmap context to draw the pixel into.
    NSInteger pointX = trunc(point.x);
    NSInteger pointY = trunc(point.y);
    CGImageRef cgImage = image.CGImage;
    NSUInteger width = image.size.width;
    NSUInteger height = image.size.height;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int bytesPerPixel = 4;
    int bytesPerRow = bytesPerPixel * 1;
    NSUInteger bitsPerComponent = 8;
    unsigned char pixelData[4] = { 0, 0, 0, 0 };
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextSetBlendMode(context, kCGBlendModeCopy);

    // Draw the pixel we are interested in onto the bitmap context
    CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
    CGContextRelease(context);

    // Convert color values [0..255] to floats [0.0..1.0]
    CGFloat red   = (CGFloat)pixelData[0] / 255.0f;
    CGFloat green = (CGFloat)pixelData[1] / 255.0f;
    CGFloat blue  = (CGFloat)pixelData[2] / 255.0f;
    CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
Swift 5:

公共扩展UIImage{
func getPixelColor(u点:CGPoint)->UIColor{
guard let cgImage=self.cgImage else{
返回UIColor.clear
}
返回cgImage.getPixelColor(点)
}
}
公共扩展CGBitmapInfo{
//看https://stackoverflow.com/a/60247648/1765629
//我把它扩展到包括
枚举组件布局{
案例a
案例bgra
案例abgr
案例argb
案例rgba
案例bgr
案例rgb
变量计数:Int{
切换自身{
案例a:返回1
case.bgr、.rgb:返回3
默认值:返回4
}
}
}
var isAlphaPremultiplied:Bool{
设alphaInfo=CGImageAlphaInfo(rawValue:rawValue&Self.alphaInfoMask.rawValue)
返回alphaInfo=.premultipliedFirst | | alphaInfo==.premultipliedLast
}
//[…]跳过其余部分
}
公共扩展CGImage{
func getPixelColor(u点:CGPoint)->UIColor{
保护let pixelData=self.dataProvider?.data,let layout=bitmapInfo.componentLayout,let data=CFDataGetBytePtr(pixelData)else{
返回,完毕
}
设x=Int(点x)
设y=Int(点y)
设w=自宽
设h=自身高度
设指数=w*y+x
设numBytes=CFDataGetLength(pixelData)
让numComponents=layout.count
如果numBytes!=w*h*numComponents{
NSLog(“意外大小:\(numBytes)!=\(w)x\(h)x\(numComponents)”)
返回,完毕
}
设isAlphaPremultiplied=bitmapInfo.isAlphaPremultiplied
开关组件{
案例1:
返回UIColor(红色:0,绿色:0,蓝色:0,alpha:CGFloat(数据[索引])/255.0)
案例3:
设c0=CGFloat((数据[3*索引])/255
设c1=CGFloat((数据[3*索引+1]))/255
设c2=CGFloat((数据[3*索引+2]))/255
如果布局==.bgr{
返回UIColor(红色:c2,绿色:c1,蓝色:c0,alpha:1.0)
}
返回UIColor(红色:c0,绿色:c1,蓝色:c2,阿尔法:1.0)
案例4:
设c0=CGFloat((数据[4*索引])/255
设c1=CGFloat((数据[4*索引+1]))/255
设c2=CGFloat((数据[4*索引+2]))/255
设c3=CGFloat((数据[4*索引+3]))/255
变量r:CGFloat=0
变量g:CGFloat=0
变量b:CGFloat=0
变量a:CGFloat=0
交换机布局{
案例.abgr:
a=c0;b=c1;g=c2;r=c3
案例.argb:
a=c0;r=c1;g=c2;b=c3
案例:bgra:
b=c0;g=c1;r=c2;a=c3
案例.rgba:
r=c0;g=c1;b=c2;a=c3
违约:
打破
}
如果isAlphaPremultiplied&&a>0{
r=r/a
g=g/a
b=b/a
}
返回UIColor(红色:r、绿色:g、蓝色:b、alpha:a)
违约:
返回,完毕
}
}
我试图重构它以使用范围,但这似乎不起作用

let start=numComponents*索引
let end=numComponents*(索引+1)
设c=data[start..
Swift 5版

此处给出的答案要么过时,要么不正确,因为它们没有考虑以下因素:

  • 图像的像素大小可以不同于由
    image.size.width
    /
    image.size.height
    返回的点大小
  • 图像中的像素组件可以使用各种布局,如BGRA、ABGR、ARGB等,也可以根本没有alpha组件,如BGR和RGB。例如,
    UIView.drawHierarchy(in:AfterCreenUpdate:)
    方法可以生成BGRA图像
  • 对于图像中的所有像素,颜色分量可以由alpha预乘,并且需要除以alpha以恢复原始颜色
  • 对于
    CGImage
    使用的内存优化,以字节为单位的像素行的大小可以大于像素宽度乘以4的大小
  • 下面的代码提供了一个通用的Swift 5解决方案,用于在所有此类特殊情况下获得像素的
    UIColor
    。该代码针对可用性和清晰度而不是性能进行了优化

    公共扩展UIImage{
    像素宽度:Int{
    返回cgImage?.width±0
    }
    可变像素高度:
    
    - (UIColor *)colorAtPixel:(CGPoint)point inImage:(UIImage *)image {
    
        if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), point)) {
            return nil;
        }
    
        // Create a 1x1 pixel byte array and bitmap context to draw the pixel into.
        NSInteger pointX = trunc(point.x);
        NSInteger pointY = trunc(point.y);
        CGImageRef cgImage = image.CGImage;
        NSUInteger width = image.size.width;
        NSUInteger height = image.size.height;
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        int bytesPerPixel = 4;
        int bytesPerRow = bytesPerPixel * 1;
        NSUInteger bitsPerComponent = 8;
        unsigned char pixelData[4] = { 0, 0, 0, 0 };
        CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
        CGColorSpaceRelease(colorSpace);
        CGContextSetBlendMode(context, kCGBlendModeCopy);
    
        // Draw the pixel we are interested in onto the bitmap context
        CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
        CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
        CGContextRelease(context);
    
        // Convert color values [0..255] to floats [0.0..1.0]
        CGFloat red   = (CGFloat)pixelData[0] / 255.0f;
        CGFloat green = (CGFloat)pixelData[1] / 255.0f;
        CGFloat blue  = (CGFloat)pixelData[2] / 255.0f;
        CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
        return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
    }
    
    extension CGImage {
        func pixel(x: Int, y: Int) -> (r: Int, g: Int, b: Int, a: Int)? { // swiftlint:disable:this large_tuple
            guard let pixelData = dataProvider?.data,
                let data = CFDataGetBytePtr(pixelData) else { return nil }
    
            let pixelInfo = ((width  * y) + x ) * 4
    
            let red = Int(data[pixelInfo])         // If you need this info, enable it
            let green = Int(data[(pixelInfo + 1)]) // If you need this info, enable it
            let blue = Int(data[pixelInfo + 2])    // If you need this info, enable it
            let alpha = Int(data[pixelInfo + 3])   // I need only this info for my maze game
    
            return (red, green, blue, alpha)
        }
    }