簡體   English   中英

如何獲取iphone上圖像上像素的RGB值

[英]How to get the RGB values for a pixel on an image on the iphone

我正在編寫一個iPhone應用程序,並且需要在photoshop中實現與“eyedropper”工具相當的東西,在那里你可以觸摸圖像上的一個點並捕獲相關像素的RGB值,以確定和匹配它的顏色。 獲取UIImage是一個簡單的部分,但有沒有辦法將UIImage數據轉換為位圖表示,我可以在其中提取給定像素的信息? 一個工作代碼示例將是最受歡迎的,並注意我不關心alpha值。

更多細節......

我今天早些時候發布了一個合並,並在此頁面上說了一些小補充 - 可以在這篇文章的底部找到。 我正在編輯帖子,但是,發布我的建議(至少對我的要求,包括修改像素數據)一個更好的方法,因為它提供可寫數據(而我據了解,提供的方法)通過以前的帖子和這篇文章的底部提供了對數據的只讀參考。

方法1:可寫像素信息

  1. 我定義了常量

     #define RGBA 4 #define RGBA_8_BIT 8 
  2. 在我的UIImage子類中,我聲明了實例變量:

     size_t bytesPerRow; size_t byteCount; size_t pixelCount; CGContextRef context; CGColorSpaceRef colorSpace; UInt8 *pixelByteData; // A pointer to an array of RGBA bytes in memory RPVW_RGBAPixel *pixelData; 
  3. 像素結構(此版本中帶有alpha)

     typedef struct RGBAPixel { byte red; byte green; byte blue; byte alpha; } RGBAPixel; 
  4. 位圖功能(返回預先計算的RGBA;將RGB除以A得到未修改的RGB):

     -(RGBAPixel*) bitmap { NSLog( @"Returning bitmap representation of UIImage." ); // 8 bits each of red, green, blue, and alpha. [self setBytesPerRow:self.size.width * RGBA]; [self setByteCount:bytesPerRow * self.size.height]; [self setPixelCount:self.size.width * self.size.height]; // Create RGB color space [self setColorSpace:CGColorSpaceCreateDeviceRGB()]; if (!colorSpace) { NSLog(@"Error allocating color space."); return nil; } [self setPixelData:malloc(byteCount)]; if (!pixelData) { NSLog(@"Error allocating bitmap memory. Releasing color space."); CGColorSpaceRelease(colorSpace); return nil; } // Create the bitmap context. // Pre-multiplied RGBA, 8-bits per component. // The source image format will be converted to the format specified here by CGBitmapContextCreate. [self setContext:CGBitmapContextCreate( (void*)pixelData, self.size.width, self.size.height, RGBA_8_BIT, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast )]; // Make sure we have our context if (!context) { free(pixelData); NSLog(@"Context not created!"); } // Draw the image to the bitmap context. // The memory allocated for the context for rendering will then contain the raw image pixelData in the specified color space. CGRect rect = { { 0 , 0 }, { self.size.width, self.size.height } }; CGContextDrawImage( context, rect, self.CGImage ); // Now we can get a pointer to the image pixelData associated with the bitmap context. pixelData = (RGBAPixel*) CGBitmapContextGetData(context); return pixelData; } 

只讀數據(以前的信息) - 方法2:


步驟1.我聲明了一個字節類型:

 typedef unsigned char byte;

第2步。我聲明了一個與像素對應的結構:

 typedef struct RGBPixel{
    byte red;
    byte green;
    byte blue;  
    }   
RGBPixel;

第3步。我將UIImageView子類化並聲明(具有相應的合成屬性):

//  Reference to Quartz CGImage for receiver (self)  
CFDataRef bitmapData;   

//  Buffer holding raw pixel data copied from Quartz CGImage held in receiver (self)    
UInt8* pixelByteData;

//  A pointer to the first pixel element in an array    
RGBPixel* pixelData;

步驟4.子類代碼我放入一個名為bitmap的方法(返回位圖像素數據):

//Get the bitmap data from the receiver's CGImage (see UIImage docs)  
[self setBitmapData: CGDataProviderCopyData(CGImageGetDataProvider([self CGImage]))];

//Create a buffer to store bitmap data (unitialized memory as long as the data)    
[self setPixelBitData:malloc(CFDataGetLength(bitmapData))];

//Copy image data into allocated buffer    
CFDataGetBytes(bitmapData,CFRangeMake(0,CFDataGetLength(bitmapData)),pixelByteData);

//Cast a pointer to the first element of pixelByteData    
//Essentially what we're doing is making a second pointer that divides the byteData's units differently - instead of dividing each unit as 1 byte we will divide each unit as 3 bytes (1 pixel).    
pixelData = (RGBPixel*) pixelByteData;

//Now you can access pixels by index: pixelData[ index ]    
NSLog(@"Pixel data one red (%i), green (%i), blue (%i).", pixelData[0].red, pixelData[0].green, pixelData[0].blue);

//You can determine the desired index by multiplying row * column.    
return pixelData;

第5步。我制作了一個訪問方法:

-(RGBPixel*)pixelDataForRow:(int)row column:(int)column{
    //Return a pointer to the pixel data
    return &pixelData[row * column];           
}

這是我對UIImage采樣顏色的解決方案。

此方法將請求的像素渲染為1px大型RGBA緩沖區,並將生成的顏色值作為UIColor對象返回。 這比我見過的大多數其他方法快得多,並且只使用很少的內存。

對於像顏色選擇器這樣的東西,它應該可以很好地工作,在任何給定的時間你通常只需要一個特定像素的值。

的UIImage + Picker.h

#import <UIKit/UIKit.h>


@interface UIImage (Picker)

- (UIColor *)colorAtPosition:(CGPoint)position;

@end

的UIImage + Picker.m

#import "UIImage+Picker.h"


@implementation UIImage (Picker)

- (UIColor *)colorAtPosition:(CGPoint)position {

    CGRect sourceRect = CGRectMake(position.x, position.y, 1.f, 1.f);
    CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, sourceRect);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *buffer = malloc(4);
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
    CGContextRef context = CGBitmapContextCreate(buffer, 1, 1, 8, 4, colorSpace, bitmapInfo);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0.f, 0.f, 1.f, 1.f), imageRef);
    CGImageRelease(imageRef);
    CGContextRelease(context);

    CGFloat r = buffer[0] / 255.f;
    CGFloat g = buffer[1] / 255.f;
    CGFloat b = buffer[2] / 255.f;
    CGFloat a = buffer[3] / 255.f;

    free(buffer);

    return [UIColor colorWithRed:r green:g blue:b alpha:a];
}

@end 

您無法直接訪問UIImage的位圖數據。

您需要獲取UIImage的CGImage表示。 然后從位圖的CFData表示中獲取CGImage的數據提供程序。 確保在完成后釋放CFData。

CGImageRef cgImage = [image CGImage];
CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
CFDataRef bitmapData = CGDataProviderCopyData(provider);

您可能希望查看CGImage的位圖信息以獲取像素順序,圖像尺寸等。

Lajos的回答對我有用。 為了將像素數據作為字節數組,我這樣做了:

UInt8* data = CFDataGetBytePtr(bitmapData);

更多信息:CFDataRef 文檔

另外,請記住包含CoreGraphics.framework

感謝大家! 將這些答案中的一些放在一起我得到:

- (UIColor*)colorFromImage:(UIImage*)image sampledAtPoint:(CGPoint)p {
    CGImageRef cgImage = [image CGImage];
    CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
    CFDataRef bitmapData = CGDataProviderCopyData(provider);
    const UInt8* data = CFDataGetBytePtr(bitmapData);
    size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    int col = p.x*(width-1);
    int row = p.y*(height-1);
    const UInt8* pixel = data + row*bytesPerRow+col*4;
    UIColor* returnColor = [UIColor colorWithRed:pixel[0]/255. green:pixel[1]/255. blue:pixel[2]/255. alpha:1.0];
    CFRelease(bitmapData);
    return returnColor;
}

對於x和y,這只需要0.0-1.0的點范圍。 例:

UIColor* sampledColor = [self colorFromImage:image
         sampledAtPoint:CGPointMake(p.x/imageView.frame.size.width,
                                    p.y/imageView.frame.size.height)];

這對我很有用。 我做了幾個像每像素位和RGBA色彩空間的假設,但這應該適用於大多數情況。

另一個注意事項 - 它在我的模擬器和設備上工作 - 我過去遇到了問題,因為它在設備上發生時發生了PNG優化。

使用ANImageBitmapRep ,它提供像素級訪問(讀/寫)。

為了在我的應用程序中做類似的事情,我創建了一個小的屏幕外CGImageContext,然后將UIImage渲染到它中。 這使我能夠快速地一次提取多個像素。 這意味着您可以使用易於解析的格式設置目標位圖,並讓CoreGraphics在顏色模型或位圖格式之間進行轉換。

我不知道如何根據給定的X,Y坐標正確地索引圖像數據。 有人知道嗎?

pixelPosition =(x +(y *((imagewidth)* BytesPerPixel)));

//據我所知,音調不是這個設備的問題,可以讓它為零... //(或者從數學中拉出來)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM