11

特定のポイントの画像のピクセル カラーを取得する方法については、いくつかの質問/回答があります。ただし、これらの回答はすべて、大きな画像 (たとえば、1000 x 1300 のように小さい場合でも) では非常に遅くなります (100 ~ 500 ミリ秒)

そこにあるコードサンプルのほとんどは、画像コンテキストを描画します。それらはすべて、実際の抽選が行われるときに時間がかかります。

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私が作成しているインスタンスではなく、ディスクからデータを読み取っているようにも見えます。

ここに画像の説明を入力

さて、この方法は、いくつかの非公式のテストでより優れたパフォーマンスを発揮しますが、それでも私が望んでいるほど高速ではありません. 基礎となるピクセルデータを取得するさらに高速な方法を知っている人はいますか???

4

4 に答える 4

6

このイメージを OpenGL ES 経由で画面に描画できる場合は、iOS 5.0 で導入されたテクスチャ キャッシュを介して、iOS 5.0 の基になるピクセルに非常に高速にランダム アクセスできます。これらは、OpenGL ES テクスチャ (画像が存在する場所) に格納されている基になる BGRA ピクセル データへの直接メモリ アクセスを可能にし、そのテクスチャから任意のピクセルをほぼ瞬時に選択できます。

私はこれを使用して、大きな (2048x2048) 画像の生のピクセル データを読み戻します。読み取り時間は、最悪の場合、それらのピクセルをすべてプルダウンするのに 10 ~ 20 ミリ秒の範囲です。繰り返しになりますが、バイト配列内の場所から読み取るだけなので、単一のピクセルへのランダムアクセスにはほとんど時間がかかりません。

もちろん、これは、特定の画像を解析して OpenGL ES にアップロードする必要があることを意味します。これには、ディスクからの読み取りと、Core Graphics との対話 (UIImage を経由する場合) が含まれます。ディスク上のランダムなPNGからピクセルデータを読み取りますが、一度レンダリングして複数回サンプリングするだけでよいようです。もしそうなら、OpenGL ES と iOS 5.0 のテクスチャ キャッシュは、このピクセル データを画面上に表示するための最速の方法です。

これらのプロセスは、オープン ソースのGPUImageフレームワーク内の GPUImagePicture (画像のアップロード) クラスと GPUImageRawData (素早い生データ アクセス) クラスにカプセル化されています。

于 2012-05-02T04:11:35.237 に答える
4

描画された (フレーム バッファー内の) ピクセルにアクセスする方法をまだ見つけていません。私が測定した最速の方法は次のとおりです。

  1. イメージの作成時に kCGImageSourceShouldCache を指定して、イメージをキャッシュすることを示します。
  2. (オプション) レンダリングを強制してイメージを事前にキャッシュします。
  3. 画像を 1x1 ビットマップ コンテキストで描画します。

このメソッドのコストは、キャッシュされたビットマップであり、関連付けられている CGImage の存続期間がある場合があります。コードは次のようになります。

  1. 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);
    
  2. 画像の事前キャッシュ

    UIGraphicsBeginImageContext(CGSizeMake(1, 1));
    [image drawAtPoint:CGPointZero];
    UIGraphicsEndImageContext();
    
  3. 画像を 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 値があります。

于 2012-09-11T17:24:08.070 に答える
1

CGImage コンテキストはおそらくほとんど空で、最初のピクセルを読み取ったり描画したりするまで実際のピクセル データは含まれていません。まだ得るものは何もありません。

PNG ファイルからピクセルを読み取ろうとしていますか? ファイルの直後に移動して、mmap し、PNG 形式を自分でデコードしてみることができます。ストレージからデータを取得するには、まだしばらく時間がかかります。

于 2012-05-02T00:08:26.320 に答える
-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;
}
于 2012-07-14T06:10:49.713 に答える