iPhoneで画像処理
続いて、画素単位へのアクセスを行います。
案外簡単な作業だと思うんですが、この処理を行うにはいろいろと手続きを踏まないと行けません。
UIImage型から画素単位までアクセスし、再びUIImageに戻す手続きは次のデータ型を経ます。
UIImage → CGImageRef → CFDataRef → CGImageRef →UIImage
実に面倒です。おまけに、CGImageRefからCFDataRefへ変換する際にはmallocが発生するので、
処理時間もかかってしまいます。
では具体的にコードを書いて行きます。
CGImageRef cg = inputImage.image.CGImage; size_t height = CGImageGetHeight(cg); size_t width = CGImageGetWidth(cg); size_t bytesPerRow = CGImageGetBytesPerRow(cg); size_t bitsPerPixel = CGImageGetBitsPerPixel(cg); CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(cg)); UInt8* pixel = (UInt8*)CFDataGetBytePtr(dataRef); // 処理内容 for( int h = 0; h < height; ++h){ for (int w = 0; w < width; ++w) { UInt8* buf = pixel + h * bytesPerRow + w * bitsPerPixel / 8; UInt8 r, g, b; // rgb値取得 r = *(buf + 0); g = *(buf + 1); b = *(buf + 2); // rgbを入れ替えて値出力 *(buf+0) = b; *(buf+1) = g; *(buf+2) = r; } } CFDataRef dst = CFDataCreate(NULL, pixel, CFDataGetLength(dataRef)); CGDataProviderRef dstDataProvider = CGDataProviderCreateWithCFData(dst); CGImageRef dstCGImage = CGImageCreate(width, height, CGImageGetBitsPerComponent(cg), bitsPerPixel, bytesPerRow,CGImageGetColorSpace(cg), CGImageGetBitmapInfo(cg),dstDataProvider, NULL, CGImageGetShouldInterpolate(cg),CGImageGetRenderingIntent(cg)); UIImage *dstUIImage = [UIImage imageWithCGImage:dstCGImage]; outputImage.image = dstUIImage; CGImageRelease(dstCGImage); CFRelease(dst); CFRelease(dataRef); CFRelease(dstDataProvider);
UIImageからCGImageRefへの変換、アクセスは
CGImageRef cg = inputImage.image.CGImage;
で可能です。
その後、画像の幅、高さ、一行当たりのバイト数、一画素当たりのビット数などを取得します。
CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(cg)); UInt8* pixel = (UInt8*)CFDataGetBytePtr(dataRef);
では、CGImage型からCFDataRef型へ変換を行います。CFDataは多分汎用的に扱えるデータ型です。
画像以外にも文章、音声でも可能です。(多分)
CFDataGetBytePtrでその先頭アドレスを取得します。
処理はよくやるforループを二重にまわせば出来ます。
画素(h,w)のアドレスにアクセスするには
UInt8* buf = pixel + h * bytesPerRow + w * bitsPerPixel / 8;
でできると思います。最後の /8 はビット→バイトの変換です。あんまりマジックナンバーは使わない方がいいんだろうけど。
CFDataからUIImageへの変換は以下の手続きを踏んで行います。
CFDataRef dst = CFDataCreate(NULL, pixel, CFDataGetLength(dataRef)); CGDataProviderRef dstDataProvider = CGDataProviderCreateWithCFData(dst); CGImageRef dstCGImage = CGImageCreate(width, height, CGImageGetBitsPerComponent(cg), bitsPerPixel, bytesPerRow,CGImageGetColorSpace(cg), CGImageGetBitmapInfo(cg),dstDataProvider, NULL, CGImageGetShouldInterpolate(cg),CGImageGetRenderingIntent(cg)); UIImage *dstUIImage = [UIImage imageWithCGImage:dstCGImage];
CGImageCreate関数が実に引数が多くてどうにかならんのかと思いますが、それは仕方ないんでしょうね。
それぞれの行の変換の流れを追うと、
- ポインタpixelから始まるメモリのCFDataRefを作る
- CFDataからCGDataProviderRefを作る
- CGDataProviderRefからCGImageRefを作る
- CGImageからUIImageを作る
という流れです。もっと簡便にしてくれたらいいのにと思いますが。。。
残りの部分では,UIImageViewに貼付けたり、後処理としてリリースをしたりしています。
CFなんとか、CGなんとかで始まる関数や型はC言語ベースで、自動的にリリースされないのでご注意ください。
微分フィルタを作ってみたらこんな感じでした。
わかりづらかったから微分値を4倍してます。
0 件のコメント:
コメントを投稿