リアルタイムに加工し8bit風画像にする8bit world cameraのようなリアルタイム加工カメラ(iOS)の作り方を共有したいと思います。
8bit world cameraをリリースして1ヶ月以上経ちました。
様々なサイト様に取り上げていただきまして大変感謝しております!!
ダウンロード数の方は1万ダウンロードもいかないという大苦戦ですが、お使い頂いた方には大変喜んでいただいているので、リリースして良かったです。
比較的マイナーな部類に入るアプリだから仕方ないといえば仕方ないのかも。
このアプリはネット上の情報などを参考にして作りました。ありがとうございます。
私もiOSのリアルタイム処理カメラの作り方を共有したいと思います。
なお、今回はopenCVは使っておりません。
カメラの各ドットのRGB情報の数値を弄ることでリアルタイム加工をしております。多少面倒くさいですが、openCVのフィルターにないものも作れますので…(openCVを使ったアプリも出したいなぁ。特徴点とか使って!)
こちらのサイト様を参考に8bit world cameraを作りました。
iOSのカメラ機能を使う方法まとめ【13日目】 | Developers.IO
3つカメラアプリを作る方法があるのですが、最後の
3.AVFoundation FrameworkのAVCaptureVideoDataOutputを使用する方法
を使用しております。
(なお、このソースコードのAudioServicesPlaySystemSound(1108);
をコメントアウトするだけで、静音カメラが出来上がります。簡単ですね!)
はじめてこのソースコードを見たら、どこにカメラ画像の加工をいれればいいかわからないと思います。
私はこのようにしました。
- (UIImage *)imageFromSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
//カメラ 画像
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// ピクセルバッファのベースアドレスをロックする
CVPixelBufferLockBaseAddress(imageBuffer, 0);
// Get information of the image
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// RGBの色空間
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress,
width,
height,
8,
bytesPerRow,
colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
//追加----------------------------------------------------------------
画面全てのドットのRGBデータを取得、加工、置き換え
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
UInt8 *tmp3;
// ピクセルのポインタを取得する
tmp3 = baseAddress + j * bytesPerRow + i * 4;
// RGBの値を取得する
UInt8 r = *(tmp3+2);
UInt8 g = *(tmp3 + 1);
UInt8 b = *(tmp3);
//RGBデータの加工
//RGBのR(赤)の値が100以下なら0にします。100以上なら255にします。
if(r <= 100){
r=0;
}else if (r >100) {
r=255;
}
//RGBのG(緑)の値が100以下なら0にします。100以上なら255にします。
if(g <= 100){
g=0;
}else if (g >100) {
g=255;
}
//RGBのB(青)の値が100以下なら0にします。100以上なら255にします。
if( b <= 100){
b=0;
}else if (b >100) {
b=255;
}
//RGBデータの置き換え
*(tmp3+2) = r;
*(tmp3 + 1) = g;
*(tmp3 ) = b;
}
}
//ここまで追加-----------------------------------------------
CGImageRef cgImage = CGBitmapContextCreateImage(newContext);
CGContextRelease(newContext);
CGColorSpaceRelease(colorSpace);
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
//このあたりは変更しています
UIImage * img
= [UIImage imageWithCGImage:cgImage scale:1.0 orientation: UIImageOrientationUp];
CGImageRef imgRef = [img CGImage];
CGContextRef context;
//画像回転
int angle = 270;
switch (angle) {
case 90:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(img.size.height, img.size.width), YES, img.scale);
context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, img.size.height, img.size.width);
CGContextScaleCTM(context, 1, -1);
CGContextRotateCTM(context, M_PI_2);
break;
case 180:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(img.size.width, img.size.height), YES, img.scale);
context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, img.size.width, 0);
CGContextScaleCTM(context, 1, -1);
CGContextRotateCTM(context, -M_PI);
break;
case 270:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(img.size.height, img.size.width), YES, img.scale);
context = UIGraphicsGetCurrentContext();
CGContextScaleCTM(context, 1, -1);
CGContextRotateCTM(context, -M_PI_2);
break;
default:
return img;
break;
}
CGContextDrawImage(context, CGRectMake(0, 0, img.size.width, img.size.height), imgRef);
result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(cgImage);
return result;
}
2015/01/28追加
ヘッダーファイルに
UIImage *result;
を追加してください。
普通に表示すると、カメラ画像横向いてしまうのでこちらのサイト様の
を利用させてもらい270 度回転させています。
この部分ですが、
// ピクセルのポインタを取得する
tmp3 = baseAddress + j * bytesPerRow + i * 4;
カメラ画像のx,y(ここではj,iですが)座標のポインタを取得しています。
UInt8 r = *(tmp3+2);
UInt8 g = *(tmp3 + 1);
UInt8 b = *(tmp3);
このように座標のRGBのデータを取得します。
そうして取得したRGBデータを加工して、またもとのポインタに書き換えてやることで画像を加工します。
//RGBデータの置き換え
*(tmp3+2) = r; //加工済みの r,g,b
*(tmp3 + 1) = g;
*(tmp3 ) = b;
(このソースの加工は8色に変換するものです)
AVFoundation Frameworkは結構ややこしいですが、一度覚えてしまえば色々できますので是非使ってみてください。
座標のRGBデータを配列に入れてあれこれしてやれば、某顔歪みカメラみたいなのもできると思います。
動画撮影も割と簡単にできると思います。ただ加工しながらの動画撮影は処理が重いのでどうなるかは試していません;
以上、8bit world cameraの参考ソースを書いてみました。