PEAKを生きる

科学の力で、能力を最大化するブログ

「蜷川実花監修カメラアプリcameranのエンジニアが教える高速フィルターカメラアプリの作り方」のレジュメを公開します

こんなかんじのフィルターが作れるようになります。

このレジュメを元にした勉強会が「MTL主催【学生限定・iPhone勉強会】蜷川実花監修カメラアプリcameranのエンジニアが教える高速フィルターカメラアプリの作り方です。 学生の皆様はふるってご参加下さい。

GitHubのリポジトリは https://github.com/kasajei/MTLSeminar201303 です。

あと、Xcodeをダウンロードしてきてね☆

Xcode App
カテゴリ: 開発ツール
価格: 無料

 

アジェンダ

  • プロジェクト作成
  • GPUImageの組み込み
  • とりあえず、GPUImageを動かしてみる
  • PIP Cameraみたいなおしゃれなフィルターを作ってみる

プロジェクト作成

  • まずプロジェクトの制作をします
  • Single View Applicationを選択

  • 名前はMTLSeminar201303にしましょう

  • 次にGPUImageをDLします

  • DLしたzipを解答して、Xcodeプロジェクトを作ったフォルダがこのようになってるように配置する

  • GPUImage-master > framework > GPUImage.xcodeproj をXcodeの左側のFrameworksの中にドロップする

  • 左の一番上のMTLSeminar201303をクリック
  • TARGETSのMTLSeminar201303をクリック
  • Build Settingsをクリック
  • 左の方にある四角で囲ったところが、Basicではなくて、Allになっていることを確認
  • 検索窓で「Header」と入力して、Header Search Pathを探す
  • 空白をダブルクリックして、+ボタンを押して、「GPUImage-master/framework/**」と入力

  • 次に、Other Linkerと検索窓で入力して、
  • Other Linker Flagに、「-ObjC」と入力

  • 次に、上のタブのSummaryをクリックしてFrameworkを下のプラスボタンをクリックして追加
    • CoreMedia.framework
    • CoreVideo.framework
    • OpenGLES.framework
    • AVFoundation.framework
    • QuartzCore.framework
    • AssetsLibrary.framework
    • libGPUImage.a

ビルドが通るかの確認

#import "ViewController.h"
#import "GPUImage.h"
#import <AssetsLibrary/AssetsLibrary.h>

@interface ViewController ()

@end

@implementation ViewController

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

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end
  • これで、command + Rで、ビルドが通るか確認しましょう
  • エラーがでれば、設定が間違っています

GUIを作る

  • resourceファイルに今回使用する、画像を入れておく(今回はフィルターに使う、iphoneとサンプルの画像が入っています)

  • こんなかんじになる

  • MainStoryboad.storyboadをクリック
  • Use Autolayoutのチェックを外しておく

  • ImageViewを探して、ドロップする
  • サイズを320 x 320ぐらいにする

  • 右サイドバーの上のタブを右から、4番目にして、imageをsample.pngにしましょう
  • すると、画像が表示されます!

  • ボタンを2つ作る
  • Round Rect Buttonを見つけてドラッグする
  • ボタンのラベルをダブルクリックすると編集できるようになるので、名前を
    • Filter
    • Save
  • としておく。

GUIとコードを紐付ける

  • command + option + returnで以下の様な画面にする

  • ImageViewをクリックして選択して、controlを押しながら、右のコードの部分にドラッグ
  • imageViewと名前をつける
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
  • が増える!

  • ボタンはアクションをつける
  • ConnectionをActionにして、pressFilterBtnとpressSaveBtnと名前をつける
- (IBAction)pressFilterBtn:(id)sender;
- (IBAction)pressSaveBtn:(id)sender;

が増える!

  • ここで、ViewController.mファイルを開くと、
- (IBAction)pressFilterBtn:(id)sender {
}

- (IBAction)pressSaveBtn:(id)sender {  
} 
  • というコードが増えている。 -この中に、コードを書くと、ボタンを押した時に、そのコードが実行される
  • 試しにログを出してみる
- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
}
  • これで、実行して、コンソールにボタンを押した!と表示されれば成功!

これで、GUIとコードがひも付きましたね!

いよいよフィルター!

フィルターボタンを押した時に、コードが動くようになったので、このメソッドの中で、画像にフィルターがかかるようにしましょう。

セピアフィルター

セピアフィルターを作ってみましょう

- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
    // GUIで設定した画像を取得する
    UIImage *inputImage = self.imageView.image;
    
    // 画像をGPUImageのフォーマットに治す
    GPUImagePicture *imagePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
    
    // セピアフィルターを作る
    GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    // イメージをセピアフィルターにくっつける
    [imagePicture addTarget:sepiaFilter];
    
    // フィルターを実行
    [imagePicture processImage];
    // 実行したフィルターから、画像を取得する
    UIImage *outputImage = [sepiaFilter imageFromCurrentlyProcessedOutput];
    
    // 取得した画像をセットする
    self.imageView.image = outputImage;

}

こんなかんじのフィルターが作れました!

ブレンドモードで、iPhoneを表示してみる

- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
    // GUIで設定した画像を取得する
    UIImage *inputImage = self.imageView.image;
    
    // 画像をGPUImageのフォーマットに治す
    GPUImagePicture *imagePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
    
    // セピアフィルターを作る
    GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    // イメージをセピアフィルターにくっつける
    [imagePicture addTarget:sepiaFilter];
    
    
    // iPhoneを表示する
    // iPhoneの画像を用意する
    UIImage *iphone = [UIImage imageNamed:@"iphone.png"];
    GPUImagePicture *iphoneImg = [[GPUImagePicture alloc] initWithImage:iphone];
    
    // 画像を合成するためのブレンドモードを作る
    GPUImageNormalBlendFilter *nomalBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // ブレンドする
    [sepiaFilter addTarget:nomalBlend]; // こっちがブレンドの下になる画像
    [iphoneImg addTarget:nomalBlend atTextureLocation:1]; // こっちが上になる画像
    
    // フィルターを実行
    [imagePicture processImage];
    [iphoneImg processImage];
    // 実行したフィルターから、画像を取得する
    UIImage *outputImage = [nomalBlend imageFromCurrentlyProcessedOutput];
    
    // 取得した画像をセットする
    self.imageView.image = outputImage;

}

でかいので小さくする

- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
    // GUIで設定した画像を取得する
    UIImage *inputImage = self.imageView.image;
    
    // 画像をGPUImageのフォーマットに治す
    GPUImagePicture *imagePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
    
    // セピアフィルターを作る
    GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    // イメージをセピアフィルターにくっつける
    [imagePicture addTarget:sepiaFilter];
    
    
    // iPhoneを表示する
    // iPhoneの画像を用意する
    UIImage *iphone = [UIImage imageNamed:@"iphone.png"];
    GPUImagePicture *iphoneImg = [[GPUImagePicture alloc] initWithImage:iphone];
    
    // 画像を合成するためのブレンドモードを作る
    GPUImageNormalBlendFilter *nomalBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // iPhoneの画像を変形するためのフィルターを作る
    GPUImageTransformFilter *transform = [[GPUImageTransformFilter alloc] init];
    
    // 変形をどうするかを決める
    CGAffineTransform trans;
    trans = CGAffineTransformMakeScale(0.75, 0.75); // 縮小
    trans = CGAffineTransformTranslate(trans, 0, 0.5); // 移動
    [transform setAffineTransform:trans];
    
    // iPhoneの画像を変形する
    [iphoneImg addTarget:transform];
    
    // ブレンドする
    [sepiaFilter addTarget:nomalBlend]; // こっちがブレンドの下になる画像
    // 変形後のiPhoneのイメージを繋げる
    [transform addTarget:nomalBlend atTextureLocation:1]; // こっちが上になる画像
    
    // フィルターを実行
    [imagePicture processImage];
    [iphoneImg processImage];
    // 実行したフィルターから、画像を取得する
    UIImage *outputImage = [nomalBlend imageFromCurrentlyProcessedOutput];
    
    // 取得した画像をセットする
    self.imageView.image = outputImage;

}

iPhoneの中に画像を入れる

- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
    // GUIで設定した画像を取得する
    UIImage *inputImage = self.imageView.image;
    
    // 画像をGPUImageのフォーマットに治す
    GPUImagePicture *imagePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
    
    // セピアフィルターを作る
    GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    // イメージをセピアフィルターにくっつける
    [imagePicture addTarget:sepiaFilter];
    
    
    // iPhoneを表示する
    // iPhoneの画像を用意する
    UIImage *iphone = [UIImage imageNamed:@"iphone.png"];
    GPUImagePicture *iphoneImg = [[GPUImagePicture alloc] initWithImage:iphone];
    
    // 画像を合成するためのブレンドモードを作る
    GPUImageNormalBlendFilter *nomalBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // iPhoneの画像を変形するためのフィルターを作る
    GPUImageTransformFilter *transform = [[GPUImageTransformFilter alloc] init];
    
    // 変形をどうするかを決める
    CGAffineTransform trans;
    trans = CGAffineTransformMakeScale(0.75, 0.75); // 縮小
    trans = CGAffineTransformTranslate(trans, 0, 0.5); // 移動
    [transform setAffineTransform:trans];
    
    // iPhoneの画像を変形する
    [iphoneImg addTarget:transform];
    
    // ブレンドする
    [sepiaFilter addTarget:nomalBlend]; // こっちがブレンドの下になる画像
    // 変形後のiPhoneのイメージを繋げる
    [transform addTarget:nomalBlend atTextureLocation:1]; // こっちが上になる画像
    
    
    // iPhoneの中に元の画像を入れるためのブレンド
    GPUImageNormalBlendFilter *insideImageBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // iPhoneの中に画像を入れるための変形
    GPUImageTransformFilter *insideTrans = [[GPUImageTransformFilter alloc] init];
    
    // iPhoneの中に画像を入れるための変形を決める
    CGAffineTransform transImg;
    transImg = CGAffineTransformMakeScale(0.64, 0.64);
    transImg = CGAffineTransformTranslate(transImg, 0.0, 1.05);
    [insideTrans setAffineTransform:transImg];

    // セピアを変形させる
    [sepiaFilter addTarget:insideTrans];
    
    // 変形させたものを合成する
    [nomalBlend addTarget:insideImageBlend];
    [insideTrans addTarget:insideImageBlend atTextureLocation:1];
    
    
    // フィルターを実行
    [imagePicture processImage];
    [iphoneImg processImage];
    // 実行したフィルターから、画像を取得する
    UIImage *outputImage = [insideImageBlend imageFromCurrentlyProcessedOutput];
    
    // 取得した画像をセットする
    self.imageView.image = outputImage;

}

下の画像をセピアじゃなくてぼかして完成!

- (IBAction)pressFilterBtn:(id)sender {
    NSLog(@"ボタンを押した!");
    // GUIで設定した画像を取得する
    UIImage *inputImage = self.imageView.image;
    
    // 画像をGPUImageのフォーマットに治す
    GPUImagePicture *imagePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
    
    // セピアフィルターを作る
    GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    // イメージをセピアフィルターにくっつける
    [imagePicture addTarget:sepiaFilter];
    
    
    // ぼかしフィルターを作る
    GPUImageGaussianBlurFilter *blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
    [blurFilter setBlurSize:4];
    
    // イメージをブラーフィルターにくっつける
    [imagePicture addTarget:blurFilter];
    
    
    // iPhoneを表示する
    // iPhoneの画像を用意する
    UIImage *iphone = [UIImage imageNamed:@"iphone.png"];
    GPUImagePicture *iphoneImg = [[GPUImagePicture alloc] initWithImage:iphone];
    
    // 画像を合成するためのブレンドモードを作る
    GPUImageNormalBlendFilter *nomalBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // iPhoneの画像を変形するためのフィルターを作る
    GPUImageTransformFilter *transform = [[GPUImageTransformFilter alloc] init];
    
    // 変形をどうするかを決める
    CGAffineTransform trans;
    trans = CGAffineTransformMakeScale(0.75, 0.75); // 縮小
    trans = CGAffineTransformTranslate(trans, 0, 0.5); // 移動
    [transform setAffineTransform:trans];
    
    // iPhoneの画像を変形する
    [iphoneImg addTarget:transform];
    
    // ブレンドする
    [blurFilter addTarget:nomalBlend]; // こっちがブレンドの下になる画像
    // 変形後のiPhoneのイメージを繋げる
    [transform addTarget:nomalBlend atTextureLocation:1]; // こっちが上になる画像
    
    
    // iPhoneの中に元の画像を入れるためのブレンド
    GPUImageNormalBlendFilter *insideImageBlend = [[GPUImageNormalBlendFilter alloc] init];
    
    // iPhoneの中に画像を入れるための変形
    GPUImageTransformFilter *insideTrans = [[GPUImageTransformFilter alloc] init];
    
    // iPhoneの中に画像を入れるための変形を決める
    CGAffineTransform transImg;
    transImg = CGAffineTransformMakeScale(0.64, 0.64);
    transImg = CGAffineTransformTranslate(transImg, 0.0, 1.05);
    [insideTrans setAffineTransform:transImg];

    // セピアを変形させる
    [sepiaFilter addTarget:insideTrans];
    
    // 変形させたものを合成する
    [nomalBlend addTarget:insideImageBlend];
    [insideTrans addTarget:insideImageBlend atTextureLocation:1];
    
    
    // フィルターを実行
    [imagePicture processImage];
    [iphoneImg processImage];
    // 実行したフィルターから、画像を取得する
    UIImage *outputImage = [insideImageBlend imageFromCurrentlyProcessedOutput];
    
    // 取得した画像をセットする
    self.imageView.image = outputImage;

}

概要

やってることを図示するとこんな感じ

このバリエーションでいろんなフィルターが作れるね!

フィルターをかけた、画像を保存する

- (IBAction)pressSaveBtn:(id)sender {
    UIImage *image = self.imageView.image;
    
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeImageToSavedPhotosAlbum:image.CGImage
                                 metadata:nil
                          completionBlock:^(NSURL *assetURL, NSError *error){
                              if (!error) {
                                  NSLog(@"保存成功!");
                              }
                          }
     ];
}

これで、保存もおっけー

おわりに

もうすこし、詳しく知りたい人は、前回連載で書いた、こちらのブログを参考にしてみて下さい。

GPUImageで高速フィルター!iOSカメラアプリの作り方(まとめ・サンプルコードあり) | リンゴにかじられたブログ
GPUImageで高速フィルター!iOSカメラアプリの作り方(まとめ・サンプルコードあり) | リンゴにかじられたブログ


リアルタイムでカメラから取得した画像にフィルターをかけるなどの開設もしています

それでは勉強会で!

最初にも書きましたが、このレジュメを元にした勉強会「MTL主催【学生限定・iPhone勉強会】蜷川実花監修カメラアプリcameranのエンジニアが教える高速フィルターカメラアプリの作り方」を開催します 学生の皆様はふるってご参加下さいね!