お使いのブラウザは、バージョンが古すぎます。

このサイトは、Internet Explore8・Internet Explore9には対応しておりません。
恐れ入りますが、お使いのブラウザをバージョンアップしていただきますよう宜しくお願いいたします。

iPhoneで動作する映像フィルタをつくる:GPUImage+iOSのAVFoundationフレームワークその5〜クロマキー合成

こんにちは、andyです。
今回は、GPUImageを使ったクロマキー合成をしてみたいと思います。


ただ、まだちょっと試行錯誤段階で、動画同士の合成が思うように出来ていません。そのため、今回は申し訳ないのですが、バックグラウンドを静止画を使うということで許してください。


動画同士の合成がうまくいったらまたブログ更新します。

ソース

それではいつものようにソースコードから。


ヘッダーファイルはこんな感じ。

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "GPUImage.h"

@interface VideoFilterViewController : UIViewController

- (IBAction)exportToMovie:(id)sender;

//解説-1
- (IBAction)slider:(id)sender;

@end



実装コードはこんな感じです。

#import "VideoFilterViewController.h"

@interface VideoFilterViewController ()
{
    GPUImageMovie *movieFile;
    GPUImageView *filterView;
    GPUImageChromaKeyBlendFilter *filter;
    GPUImageMovieWriter* movieWriter;
    GPUImagePicture* picture;
}

@end

@implementation VideoFilterViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	[self showFilteringMovie];
}

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

- (void)showFilteringMovie
{
    [self makeChromakeyFilter];
    
    [NSTimer scheduledTimerWithTimeInterval:0.5f
                                     target:self
                                   selector: @selector(play:)
                                   userInfo:nil
                                    repeats:NO];
    
}

- (void)makeChromakeyFilter
{
    if (filterView == nil) {
        filterView = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
    }
    
    if (movieFile) {
        [movieFile cancelProcessing];
        [movieFile removeAllTargets];
        [picture removeAllTargets];
        [filter removeAllTargets];
        movieFile = nil;
        picture = nil;
        [filterView removeFromSuperview];
    }
    
    //解説-2
    NSURL *fileURL1 = [[NSBundle mainBundle] URLForResource:@"Explosion" withExtension:@"mp4"];
    movieFile = [[GPUImageMovie alloc] initWithAsset:[AVURLAsset URLAssetWithURL:fileURL1 options:nil]];
    
    UIImage* image = [UIImage imageNamed:@"<画像ファイル>"];
    picture = [[GPUImagePicture alloc] initWithImage:image smoothlyScaleOutput:YES];
    
    filter = [[GPUImageChromaKeyBlendFilter alloc] init];
    
    //解説-3
    [filter setColorToReplaceRed:0.0 green:0.0 blue:0.99];

    [movieFile addTarget:filter];
    [picture addTarget:filter];
    
    [filter addTarget:filterView];
    [self.view addSubview:filterView];
}

- (void)play:(id)sender
{
    __weak GPUImageMovie* weakMovieFile = movieFile;
    __weak GPUImagePicture* weakPicture = picture;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        [weakPicture processImage];
        [weakMovieFile startProcessing];
    });
}

- (void)exportStart:(id)sender
{
    __weak GPUImageMovieWriter* weakMovieWriter = movieWriter;
    __weak GPUImageMovie* weakMovieFile = movieFile;
    __weak GPUImagePicture* weakPicture = picture;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [weakMovieWriter startRecording];
        [weakPicture processImage];
        [weakMovieFile startProcessing];
    });
}

- (IBAction)exportToMovie:(id)sender;
{
    [self makeChromakeyFilter];

    NSString* pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp/tmp.mov"];
    unlink([pathToMovie UTF8String]);
    NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];

    CGSize frame = CGSizeMake(640, 480);

    movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:frame fileType:AVFileTypeQuickTimeMovie outputSettings:nil];
    
    [filter addTarget:movieWriter];
    [movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
    
    [NSTimer scheduledTimerWithTimeInterval:1.0f
                                     target:self
                                   selector: @selector(exportStart:)
                                   userInfo:nil
                                    repeats:NO];
}

//解説-4
- (IBAction)slider:(id)sender
{
    UISlider *slider = (UISlider *)sender;
    switch (slider.tag) {
        case 10:
            filter.smoothing = slider.value;
            break;
            
        case 11:
            filter.thresholdSensitivity = slider.value;
            break;
    }
}

@end


コード解説

解説-1

クロマキーフィルタのパラメータを動的に調整するために、Storyboardで予めスライダを2つ画面に追加しておき、スライダのコールバックを取得しています。

解説-2

前回とコードが変わっていますが、やってることはあまり変わりません。今回はクロマキーでキーイングを行うための動画1ファイルと、キーイングされた部分に表示するためのバックグラウンド画像を1ファイル用意しています。

解説-3

GPUImageChromaKeyBlendFilterというフィルタを使っていますが、この部分でキーイングされる部分のRGB値を設定しています。この値は0.0〜1.0までの値を与えるのですが、予めPhotoshopなどで動画のキーイングされる部分のカラー値を取得しておいて0〜255の値を0.0〜1.0に変換しました。
実際のプログラムでは、画面をタップしてその部分のカラー値をサンプリングすると良いと思います。

解説-4

スライダからのコールバックを受けています。タグ値10がキーイングする色の範囲、タグ値11がキーイングする色の明るさのしきい値です。調整して一番きれいにキーイングされる部分に設定します。


今回は、キーイングする動画の背景色データを入れなければならない関係で、キーイングに使う動画をアップさせていただきます。背景に使う画像は適当なものを使ってください。
動画のダウンロードはこちら。


今回はここまで。
次回はまだ何するか決めてません。


それではまた。

コメントをどうぞ

メールアドレスは公開されません。* が付いている欄は必須項目です。


お気軽にお問い合わせください。

日本VTR実験室では、お仕事のご依頼、ブログ・コラムのご感想などを受け付けております。
アプリ開発・コンテンツ制作でお困りでしたら、お気軽にご相談ください。
ご連絡お待ちしております。

お問い合わせはこちらから

03-3541-1230

info@nvtrlab.jp

電話受付対応時間:平日AM9:30〜PM6:00