22

バックグラウンドスレッドでは、アプリケーションはディスクから画像を読み取り、画面のサイズ(1024x768または2048x1536)にダウンスケールして、ディスクに保存する必要があります。元の画像は主にカメラロールからのものですが、一部の画像はより大きなサイズ(3000x3000など)である場合があります。

後で、別のスレッドで、これらのイメージは頻繁に500x500前後のさまざまなサイズにダウンスケールされ、ディスクに再度保存されます。

これは私に不思議に思います:iOSでこれを行うための最も効率的な方法は、パフォーマンスとメモリの面で何ですか?私は2つの異なるAPIを使用しました:

どちらもうまくいきましたが、パフォーマンスとメモリ使用量に違いがあるのではないかと思います。もちろん、もっと良い選択肢があれば。

4

6 に答える 6

7

それが役立つとは断言できませんが、GPUに作業をプッシュすることは価値があると思います。これは、テクスチャクワッドを特定のサイズでレンダリングするか、GPUImageとそのサイズ変更機能を使用して自分で行うことができます。古いデバイスではテクスチャサイズに制限がありますが、CPUベースのソリューションよりもはるかに優れたパフォーマンスを発揮するはずです。

于 2012-11-11T16:11:27.840 に答える
5

libjpeg-turbo を使用すると、 のscale_numおよびscale_denomフィールドを使用できjpeg_decompress_struct、画像の必要なブロックのみをデコードします。4Sのバックグラウンドスレッドで、3264x2448の元の画像(カメラからの、メモリに配置された画像データ)からiPhoneのディスプレイ解像度まで、250ミリ秒のデコード+スケーリング時間を与えました。それほど大きな画像でも問題ないと思いますが、それでも素晴らしいとは言えません。

(そして、はい、それはメモリ効率が良いです。画像をほぼ1行ずつデコードして保存できます)

于 2012-11-10T21:45:28.020 に答える
4

あなたがツイッターで言ったことはあなたの質問と一致しません。

メモリ スパイクが発生している場合は、Instruments を見て、メモリを消費しているものを特定します。高解像度画像のデータだけでも 10 メガであり、アルファ チャネルが含まれていない場合、結果の画像は約 750k になります。

最初の問題は、メモリ使用量を低く抑えることです。そのためには、ロードするすべての画像が使用後すぐに破棄されるようにします。これにより、基盤となる C/Objective-C API がメモリをすぐに破棄することが保証されます。 、GC が実行されるのを待つ代わりに、次のようになります。

 using (var img = UIImage.FromFile ("..."){
     using (var scaled = Scaler (img)){
          scaled.Save (...);
     }
 }

スケーリングに関しては、画像をスケーリングするさまざまな方法があります。最も簡単な方法は、コンテキストを作成して描画し、コンテキストから画像を取得することです。これは、MonoTouch の UIImage.Scale メソッドの実装方法です。

public UIImage Scale (SizeF newSize)
{
    UIGraphics.BeginImageContext (newSize);

    Draw (new RectangleF (0, 0, newSize.Width, newSize.Height));

    var scaledImage = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();

    return scaledImage;            
}

パフォーマンスは、有効にするコンテキスト機能によって決まります。たとえば、高品質のスケーリングには、補間の品質を変更する必要があります。

 context.InterpolationQuality = CGInterpolationQuality.High

もう 1 つのオプションは、スケーリングを CPU ではなく GPU で実行することです。これを行うには、CoreImage API を使用し、CIAffineTransform フィルターを使用します。

どちらが速いかは、他の誰かがベンチマークするに任せるものです

CGImage Scale (string file)
{
    var ciimage = CIImage.FromCGImage (UIImage.FromFile (file));

    // Create an AffineTransform that makes the image 1/5th of the size
    var transform = CGAffineTransform.MakeScale (0.5f, 0.5f);

    var affineTransform = new CIAffineTransform () { 
        Image = ciimage,
        Transform = transform
    };
    var output = affineTransform.OutputImage;
    var context = CIContext.FromOptions (null);
    return context.CreateCGImage (output, output.Extent);
}
于 2012-11-11T03:49:34.073 に答える
3

どちらかが2つのうちでより効率的である場合、それは前者になります。

を作成するCGImageSourceと、その名前が示すとおりに作成されます。つまり、画像を取得できる不透明なものを作成します。あなたの場合、それはディスク上のものへの参照になります。ImageIOにサムネイルの作成を依頼するときは、「この数のピクセルを出力するために必要なだけ実行する」ことを明示的に指示します。

逆に、その時点で描画する場合はCGBitmapContext、ある時点で画像全体を明示的にメモリに取り込みます。

したがって、2番目のアプローチでは、ある時点で画像全体が一度にメモリに保存されます。逆に、前者は必ずしも必要ではありません(実際には、続行するための最良の方法に関して、ImageIO内で何らかの推測が行われることは間違いありません)。したがって、OSのすべての可能な実装全体で、前者が有利であるか、2つの間に違いはありません。

于 2012-11-07T00:30:44.520 に答える
3

レプトニカのようなcベースのライブラリを使ってみます。iOSが比較的新しいAccelerateFrameworkを使用してCoreGraphicsを最適化するかどうかはわかりませんが、CoreGraphicsには、画像のサイズを変更するためだけに、より多くのオーバーヘッドが伴う可能性があります。最後に...独自の実装をロールしたい場合は、vImageScale _ ??format??を使用してみてください いくつかのメモリマップトファイルに支えられて、私は何もより速くなるのを見ることができません。

http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/vImage/Introduction/Introduction.html

PS。また、コンパイラの最適化フラグも確認してください。

于 2012-11-10T20:45:53.513 に答える