写真.PNG

iPhoneでカラートラッキングの実験をしました。
下記のページなどを参考にしました。
(当記事は過去に別のブログに投稿したものの再掲です。)

・iOSのカメラ機能を使う方法まとめ【13日目】

#import "ViewController.h"
#import "CoreVideo/CoreVideo.h"
#import "CoreImage/CoreImage.h"
#import "CoreGraphics/CoreGraphics.h"

@interface ViewController ()

@property (strong, nonatomic) AVCaptureDeviceInput *videoInput;
@property (strong, nonatomic) AVCaptureVideoDataOutput *videoDataOutput;
@property (strong, nonatomic) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic, strong) CALayer* indicatorLayer;
@property (nonatomic, retain) CIDetector* faceDetector;
@property (weak, nonatomic) IBOutlet UIImageView *previewImageView;
@end

@implementation ViewControlle

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 撮影開始
    [self setupAVCapture];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)setupAVCapture {
    NSError *error = nil;
    
    // 入力と出力からキャプチャーセッションを作成
    self.session = [[AVCaptureSession alloc] init];
    self.session.sessionPreset = AVCaptureSessionPreset640x480;
    
    // カメラからの入力を作成
    AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    // カメラからの入力を作成し、セッションに追加
    self.videoInput = [AVCaptureDeviceInput deviceInputWithDevice:camera 
                                                            error:&error];
    [self.session addInput:self.videoInput];
    
    // 画像への出力を作成し、セッションに追加
    self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
    [self.session addOutput:self.videoDataOutput];
    
    // ビデオ出力のキャプチャの画像情報のキューを設定
    dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
    [self.videoDataOutput setAlwaysDiscardsLateVideoFrames:TRUE];
    [self.videoDataOutput setSampleBufferDelegate:self queue:queue];
    
    // ビデオへの出力の画像は、BGRAで出力
    self.videoDataOutput.videoSettings = @{
          (id)kCVPixelBufferPixelFormatTypeKey :[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
    };
    
    // ビデオ入力のAVCaptureConnectionを取得
    //AVCaptureConnection *videoConnection = [self.videoDataOutput
                          connectionWithMediaType:AVMediaTypeVideo];
    
    // 1秒あたり12回画像をキャプチャ
    if ( YES == [camera lockForConfiguration:NULL] ) {
        [camera setActiveVideoMinFrameDuration:CMTimeMake(50,600)];
        [camera setActiveVideoMaxFrameDuration:CMTimeMake(50,600)];
    }
    
    //背景
    _previewLayer =
    [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    _previewLayer.frame = self.previewImageView.bounds;
    [self.view.layer addSublayer:_previewLayer];
    
    //マーカー
    self.indicatorLayer = [CALayer layer];
    self.indicatorLayer.frame = CGRectMake(0,0,
                   self.view.bounds.size.width,self.view.bounds.size.height);
    self.indicatorLayer.hidden = NO;
    [self.view.layer addSublayer:self.indicatorLayer];
    
    [self.session startRunning];
}

// AVCaptureVideoDataOutputSampleBufferDelegateプロトコルのメソッド。
// 新しいキャプチャの情報が追加されたときに呼び出される。
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    // *** COLOR DETECTION ***
    NSArray* ledPoints = [self colorDetect:sampleBuffer];
    
    // *** DRAW ***
    UIGraphicsBeginImageContext(CGSizeMake(self.view.bounds.size.width, 
                          self.view.bounds.size.height));// オフスクリーンに描画
    CGContextRef context = UIGraphicsGetCurrentContext();
    //green
    CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);//塗り色
    CGContextAddEllipseInRect(context, 
            CGRectMake([[ledPoints objectAtIndex:0] CGPointValue].x-10, 
             [[ledPoints objectAtIndex:0] CGPointValue].y-10, 20, 20));//円の大きさ
    CGContextDrawPath(context, kCGPathFillStroke);//描く
    //red
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);//塗り色
    CGContextAddEllipseInRect(context, 
            CGRectMake([[ledPoints objectAtIndex:1] CGPointValue].x-10, 
             [[ledPoints objectAtIndex:1] CGPointValue].y-10, 20, 20));//円の大きさ
    CGContextDrawPath(context, kCGPathFillStroke);//描く
    
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();// オフスクリーン内容をUIImageに変換
    UIGraphicsEndImageContext();// オフスクリーン描画を終了
    
    // 画像を画面に表示
    dispatch_async(dispatch_get_main_queue(), ^{
        self.indicatorLayer.contents = (id)img.CGImage;//layerにイメージをセットする
    });
    img = nil;
}

// COLOR DETECTION
- (NSArray*)colorDetect:(CMSampleBufferRef)sampleBuffer
{
    CGPoint tagR = CGPointMake(0, 0);
    CGPoint tagG = CGPointMake(0, 0);
    BOOL detection_g = NO;
    BOOL detection_r = NO;
    int sumX_g = 0;
    int sumY_g = 0;
    int pixelNum_g = 0;
    int sumX_r = 0;
    int sumY_r = 0;
    int pixelNum_r = 0;
    // キャプチャしたフレームからCGImageを作成
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
    // CGImageを取得する
    CGImageRef  imageRef = image.CGImage;
    // データプロバイダを取得する
    CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef);
    // ビットマップデータを取得する
    CFDataRef dataRef = CGDataProviderCopyData(dataProvider);
    UInt8* buffer = (UInt8*)CFDataGetBytePtr(dataRef);
    CFRelease(dataRef);
     
    size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    imageRef = nil;
    NSUInteger x,y;
    UInt8 r,g,b;
    UInt8*  pixelPtr;
    for (y=0; y<height; y+=4) {
        for (x=0; x<width; x+=4) {
            // ピクセルのポインタを取得する
            pixelPtr = buffer + y * bytesPerRow + x * 4;
     
            // 色情報を取得する
            b = *(pixelPtr + 0);  // 青
            g = *(pixelPtr + 1);  // 緑
            r = *(pixelPtr + 2);  // 赤
     
            if (g > 240 && r <120 && b < 120) {
                detection_g = YES;
                sumX_g += x;  //X座標値を加算する
                sumY_g += y;   //Y座標値を加算する
                pixelNum_g++; //近似色ピクセルの個数を加算する
            }
            if (r > 240 && g <120 && b < 120) {
                detection_r = YES;
                sumX_r += x;  //X座標値を加算する
                sumY_r += y;   //Y座標値を加算する
                pixelNum_r++; //近似色ピクセルの個数を加算する
            }
            pixelPtr = nil;
        }
    }
     
    if(detection_g){
        tagG.y = sumX_g / pixelNum_g * 568 / 640;
        tagG.x = 320-sumY_g / pixelNum_g * 320 / 480;
    }
    if(detection_r){
        tagR.y = sumX_r / pixelNum_r * 568 / 640;
        tagR.x = 320-sumY_r / pixelNum_r * 320 / 480;
    }
    
    return [[NSArray alloc]initWithObjects:[NSValue valueWithCGPoint:tagG],[NSValue valueWithCGPoint:tagR],nil];
}

// サンプルバッファのデータからCGImageRefを生成する
- (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);
    
    CGImageRef cgImage = CGBitmapContextCreateImage(newContext);
    
    CGContextRelease(newContext);
    CGColorSpaceRelease(colorSpace);
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    
    UIImage *image = [UIImage imageWithCGImage:cgImage scale:1.0  
                         orientation:UIImageOrientationRight];
    
    CGImageRelease(cgImage);
    
    return image;
}
@end