UIImageのピクセルアルファ値の取得
-
22-07-2019 - |
質問
現在、UIImageViewのピクセルのアルファ値を取得しようとしています。 [UIImageView image]からCGImageを取得し、これからRGBAバイト配列を作成しました。アルファはあらかじめ乗算されています。
CGImageRef image = uiImage.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
rawData = malloc(height * width * 4);
bytesPerPixel = 4;
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), image);
CGContextRelease(context);
次に、UIImageViewの座標を使用して、指定されたアルファチャネルの配列インデックスを計算します。
int byteIndex = (bytesPerRow * uiViewPoint.y) + uiViewPoint.x * bytesPerPixel;
unsigned char alpha = rawData[byteIndex + 3];
ただし、期待する値が得られません。画像の完全に黒い透明な領域の場合、アルファチャンネルの値がゼロ以外になります。 UIKitとCore Graphicsの間の座標を変換する必要がありますか?つまり、y軸が反転していますか?または、事前に乗算されたアルファ値を誤解していませんか?
更新:
@Nikolai Ruheの提案がこれの鍵でした。実際、UIKit座標とCore Graphics座標を変換する必要はありませんでした。しかし、ブレンドモードを設定した後、私のアルファ値は私が期待したものでした:
CGContextSetBlendMode(context, kCGBlendModeCopy);
解決
はい、CGContextのy軸は上向きですが、UIKitでは下向きです。 ドキュメントを見る。
>コードを読んだ後に編集する:
前にコンテキストのバッファーにあった値ではなく、画像のアルファ値が必要なため、画像を描画する前に置換するブレンドモードを設定することもできます。
CGContextSetBlendMode(context, kCGBlendModeCopy);
考えた後に編集:
可能な限り最小のCGBitmapContext(1x1ピクセル?8x8?を試してみてください)を構築し、描画する前にコンテキストを目的の位置に変換することで、検索を非常により効率的に実行できます。
CGContextTranslateCTM(context, xOffset, yOffset);
他のヒント
必要なのが単一ポイントのアルファ値だけである場合、必要なのはアルファのみの単一ポイントバッファです。これで十分だと思います:
// assume im is a UIImage, point is the CGPoint to test
CGImageRef cgim = im.CGImage;
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 1, NULL,
kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(-point.x,
-point.y,
CGImageGetWidth(cgim),
CGImageGetHeight(cgim)),
cgim);
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;
UIImageを毎回再作成する必要がない場合、これは非常に効率的です。
2011年12月8日編集:
コメント者は、特定の状況下では画像が反転する可能性があると指摘しています。私はこれについて考えていましたが、このようにUIImageを直接使用してコードを書いていないことを少し残念に思います(理由は UIGraphicsPushContextについて理解していないからだと思います
):
// assume im is a UIImage, point is the CGPoint to test
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 1, NULL,
kCGImageAlphaOnly);
UIGraphicsPushContext(context);
[im drawAtPoint:CGPointMake(-point.x, -point.y)];
UIGraphicsPopContext();
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;
これで反転の問題は解決したと思います。
長方形の境界ボックスではなく、画像データのアルファ値を使用してスプライト間の衝突検出を行う方法を調査中に、この質問/回答を見つけました。コンテキストはiPhoneアプリです...私は上記の1ピクセル描画をしようとしていますが、これを動作させるのにまだ問題がありますが、画像自体のデータを使用してCGContextRefを作成する簡単な方法を見つけましたヘルパー関数はこちら:
CGContextRef context = CGBitmapContextCreate(
rawData,
CGImageGetWidth(cgiRef),
CGImageGetHeight(cgiRef),
CGImageGetBitsPerComponent(cgiRef),
CGImageGetBytesPerRow(cgiRef),
CGImageGetColorSpace(cgiRef),
kCGImageAlphaPremultipliedLast
);
これにより、上記のサンプルのいハードコーディングがすべてバイパスされます。最後の値はCGImageGetBitmapInfo()を呼び出すことで取得できますが、私の場合は、ContextCreate関数でエラーを引き起こした画像から値を返します。ここに記載されている特定の組み合わせのみが有効です: http://developer.apple.com/qa /qa2001/qa1037.html
これが役立つことを願っています!
UIKitとCore Graphicsの間の座標を変換する必要がありますか?つまり、y軸は逆ですか?
それは可能です。 CGImageでは、ピクセルデータは英語の読み取り順(左から右、上から下)です。したがって、配列の最初のピクセルは左上です。 2番目のピクセルは、一番上の行の左から1つです。など。
あなたがその権利を持っていると仮定すると、ピクセル内の正しいコンポーネントを見ていることも確認する必要があります。おそらく、RGBAを期待しているが、ARGBを要求している、またはその逆です。または、バイト順序が間違っている可能性があります(iPhoneのエンディアンが何であるかわかりません)。
または、事前に乗算されたアルファ値を誤解していませんか?
そのようには聞こえません。
わからない場合:事前乗算とは、色成分にアルファが事前乗算されることを意味します。アルファ成分は、色成分が事前に乗算されているかどうかに関係なく同じです。色成分をアルファで除算することで、これを逆乗算(事前乗算なし)できます。