3

OK 私は、iPhone/iPad でユーザーがインタラクティブに画像を操作するこのアプリを作成しています。これは基本的に、タッチに応じて画像を再形成するタッチ依存機能です。非常によく似たものが Facetune アプリにもあります。

私のアルゴリズムでは、タッチの動きに基づいてコントロール ポイントを計算する必要があります。次に、これらの制御点に基づいて、画像の補間に使用される合成グリッドを生成しています。私のアプローチ全体は問題なく機能しています。唯一の問題は、リアルタイムで遅いことです。私は使っている

dispatch_async(dispatch_get_main_queue(), ^{

タッチムーブ機能ではまだ遅いです。画像を約 360* に再スケーリングすると、プロセスが高速化されますが、画質が犠牲になります。

私のタッチムーブコードは次のとおりです。

- (void)updateImage
{
    int bytesPerRow = CGImageGetBytesPerRow([staticBG.image CGImage]);
    int height = CGImageGetHeight([staticBG.image CGImage]);
    int width = CGImageGetWidth([staticBG.image CGImage]);
    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider([staticBG.image CGImage]));
    unsigned char *baseImage = (unsigned char *)CFDataGetBytePtr(pixelData);

    unsigned char *output_image;
    output_image = [self wrappingInterpolation :baseImage :orig :changed :width :height :bytesPerRow];

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGContextRef context = CGBitmapContextCreate(output_image, width, height, 8, bytesPerRow, colorSpaceRef, bitmapInfo);
    CGImageRef imageRef = CGBitmapContextCreateImage (context);
    UIImage *newimage = [UIImage imageWithCGImage:imageRef];
    CGColorSpaceRelease(colorSpaceRef);
    CGContextRelease(context);
    CFRelease(imageRef);

    free(output_image);
    resultView.image = newimage;
    //staticBG.hidden = YES;
}

この方法は、リアルタイムで実行できるように高度に最適化されています。orig および changed 引数は、必要な制御点を持つ 2 つの float*float 行列です。ここでは、毎回 UIImage からピクセル データを取得し、CGImageRef、CGCOntextRef、ColorSpaceRef などを作成してから、再度解放する一定のオーバーヘッドが見られます。とにかく、これらを最適化できますか?可能であれば、他の可能なスピードアップを提案してください。しかし、私は OpenGL やシェーダーについてまったく知らないので、シェーダーを介してこれらを実行できない可能性があります。

4

1 に答える 1

1

そうです、ボトルネックはメモリ管理にあります。

生のビットマップ データを に抽出するCFDataRef pixelDataと、イメージ全体が解凍され、完全にコピーされます。次に、補間ルーチンはデータのコピーを再度作成します。このコピーは精巧に作成され、 に格納されoutput_imageます。次に、メモリを 2 回解放します。1 回はプロパティの割り当てによって解放する古いイメージ用で、もう 1 回はfree(...)コマンド用です。

数字で言えば、iPhone 5 は 3264x2448 で写真を撮ります。これは、RGB 形式で 22MB (チャンネルあたり 8b) を意味し、ラッピング ルーチンによって 2 倍になります。そして、この二重の割り当てと二重のコピー (および二重の解放) は、イベントが発生する速度で発生します。また、ルーチンが入力データの処理に使用する時間も追加する必要があります。すべてのピクセルでループすると、8MP 画像で 800 万回の反復を意味します。これには間違いなく多くの計算能力が必要です。

達成したいことは、リアルタイムのビデオ/画像処理に何らかの形で似ていることに注意してください。ビデオ処理に関しては、特定のテクニックを採用する必要があります。OpenGL は本当に最良の選択肢ですが、より多くの努力が必要です。いくつかの基本的な提案は

  • 2 回の割り当ては避けbaseImageてください。既にデータをコピーしているため、アルゴリズムでインプレース変換が許可されている場合は、直接作業してください。

  • キャッシュ イメージ データ: 毎回ビットマップ データを抽出しないでください。アルゴリズムが「相加的に」機能する場合は、同じままにCFDataRefして、毎回それに取り組んでください。

    ルーチンではstaticBG、入力データとして常に使用します。これは、アルゴリズムが常にベース イメージを変更することを示唆しています。生の画像データを一度だけキャッシュできます。

  • でラップしないでくださいUIImage:には、コンテンツを表示するために a に設定できるCALayer便利なプロパティがあります。また、あなたが行っていることは何らかの形でアニメーションに関連しているため、UIの要素を削除してCAレベルで作業することができます。これは、より柔軟 (かつ高速) です。Apple のドキュメントを参照してください。contentsCGImageRef

  • 本当に中間メモリ ストレージを使用する必要がある場合は、同じメモリを再利用してコピーします。イメージのサイズはおそらく変わらず、少なくとも割り当て時間を節約できます。

  • 最終結果を事前にレンダリングします。実際には画面のサイズで作業し、フルサイズの画像を作成するために必要な情報を保存できます。その後、後続のフェーズでそれを行います。

これらの提案により、不要な割り当てをすべて回避できます。アルゴリズムが追加的でないか、その場で実行できない場合は、コピー操作のみが残ります。アルゴリズムのいくつかの提案 (既に実装している可能性があります):

  • 可能であれば、データをその場で処理します。
  • 実際に変更されるピクセルのみをループします。
  • 作業に必要なデータのみをコピーします。
  • 可能であれば、ピクセルをベクトルとして扱い、最適化された関数を使用します。Accelerate フレームワークを見てみましょう。画像を直接操作するルーチンはたくさんあります。
  • 可能な場合はQuartz 2Dを使用してください。

それでも、最善の提案はOpenGL に切り替えることです。最良のシナリオでも、CGBitmapContextCreateImage回避できない への呼び出しという問題があります。ドキュメンテーションによると、データは CoreGraphics によってコピーされます。これは、すべてのフレームにデータの完全なコピーが少なくとも 1 つ必要であることを意味します。私の知る限り、表示されているバッファをリアルタイムで変更することはできません。最良の概算は、ほとんどハードウェア レベルで実行される OpenGL によって与えられ、EAGLContextCoreAnimation によって表示される に直接フラッシュされるバッファに書き込みます。

これは非常に異なるアプローチですが、非常に高速です。一部の視覚効果 (ガウスぼかしなど) はかなりの電力を必要としますが、OpenGL ではリアルタイムで実行されます。このGLImageProcessingを見始めることができます。これはラスター画像操作の非常に興味深い例です。さらに、OpenGL はイメージ ワーピングにも非常に適しています。イメージをプレーン メッシュ上にテクスチャとして表示し、それを変形させることができます。

于 2014-01-30T22:45:52.627 に答える