Objective-C

GPUImageでカメラアプリ作成をはじめて1時間経過。やはりハマる

More than 5 years have passed since last update.


フィルタ処理された画像を取り出すのにハマる

よーしまずは画像をセピア色にしよう!と思って、チュートリアル的なサイトを探して参考にさせていただいた。

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

その他いくつかのサイトでもここを参考に、類似の実装を行っているようだし、はじめの一歩なのでさすがに簡単そうに見えた。

さくさくと進めるかと思いきや、imageFromCurrentlyProcessedOutputセレクタが見つからず、???となってしまった。

そこで、githubのページをきちんと読み直したら解決策を見つけた。

UIImage *inputImage = [UIImage imageNamed:@"Lambeau.jpg"];

GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage];
GPUImageSepiaFilter *stillImageFilter = [[GPUImageSepiaFilter alloc] init];

[stillImageSource addTarget:stillImageFilter];
[stillImageFilter useNextFrameForImageCapture] //imageFromCurrentlyProcessedOutputを使うならその前にこれを呼び出す
[stillImageSource processImage];

UIImage *currentFilteredVideoFrame = [stillImageFilter imageFromCurrentFramebuffer]; //以前はimageFromCurrentlyProcessedOutput

githubのissuesや、本家サイトを確認してみると、


  • フレームワークのメモリ利用量の削減

  • メモリ関連のクラッシュ回避

などの観点から変更した模様。

この件、日本語の情報はまだ少ないな・・。


GPUImageView は UIImageViewではない?でハマる

次に、githubのサンプルを活用してみようと、SimpleImageFilterを弄ってみることにした。

サンプルはloadViewでGPUImageViewを初期化しているが、自分はstroyboardでUIImageViewを使ってプレースホルダ画像を活用したいと思っている。

しかし、下記の実装だと実行時エラーが出てしまう。

    /***

ここで登場するself.imageViewはstoryboardにて接続したUIImageViewのこと。
実装は、UIViewControllerのviewDidLoad内の処理。
***/

//GUIで設定した画像を取得する
UIImage *inputImage = nil;
inputImage = self.imageView.image;

//画像をGPUImageのフォーマットに変換する
GPUImagePicture *sourcePicture;
sourcePicture = [[GPUImagePicture alloc] initWithImage:inputImage smoothlyScaleOutput:YES];

//セピアフィルターを作る
GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
GPUImageView *theImageView = (GPUImageView *)self.imageView; //キャストしてるんだけど・・。
[self.sepiaFilter forceProcessingAtSize:theImageView.sizeInPixels];

//ターゲット設定する
[sourcePicture addTarget:sepiaFilter];
[self.sepiaFilter addTarget:theImageView]

//フィルターを実行
[sourcePicture processImage];

エラーログの一部はこのような感じで、キャストしているんだけどGPUImageVIewのアクセサメソッドが認識されないようだ。ログを見れば[UIImageView sizeInPixels]とあり、確かにこの文字列だけ見たら通らないな、とは思うのだけど・・。

-[UIImageView sizeInPixels]: unrecognized selector sent to instance ...

直接関係ないが、 http://stackoverflow.com/a/23747248 にライブラリ作者様のコメントがある。


GPUImageView is not a subclass of UIImageView.


今回の件は、サブクラスではないけど一応ダウンキャスト(サブクラスへのキャスト)としてコンパイルできるものの、結局は定義していないメソッドの実行箇所で落ちる、ということだろうか。

そもそもダウンキャスト自体が危険なアプローチになることが多いらしいので注意が必要だ。

カメラアプリの開発を進める中で、もう少し深堀できると良い。