6

.NET では、通常、Bitmap クラスを使用して画像を保存します。すばやくアクセスするには、lock() と unlock()を呼び出して、ビットマップの内容をメモリにコピーする必要があります。では、ロックする前にビットマップがパックされたメモリ配列に格納されていなかったということですか?

ロックの必要性は正確には何ですか?つまり、プラットフォームが単純にビットマップの最初のピクセルへのポインターを返すことができず、ピクセルに直接アクセスできないのはなぜですか? (「安全でない」メモリアクセスの考慮事項は別として)

考えられる理由:

  • ビットマップは、メモリを節約するために元の圧縮形式 (PNG、JPEG など) で保存されます。
  • ビットマップは 24 bpp 形式で保存されるため、32 bpp イメージよりもアクセスが遅くなります
  • ビットマップはパックされたメモリ配列に格納されておらず、断片化されているため、高速に読み書きできません
  • ビットマップは非公開の方法で保存されており、プラットフォームは実際のビットマップ データ メモリにアクセスすることを望んでおらず、lock() を使用してメモリ内にコピーを作成する必要があります。
4

3 に答える 3

12

ビットマップは遅延方式で読み取られます。使用される実際のアルゴリズムは、画像形式に大きく依存します。.bmp ファイルは簡単ですが、.jpeg ファイルはそれほど簡単ではありません。内部的には、GDI+ は、必要に応じて、オペレーティング システムのデマンド ページ仮想メモリ マッピング機能を利用して、ファイル データを RAM にマップするメモリ マップ ファイルを作成します。この MMF は、悪名高くファイルにロックを作成し、画像を同じ名前のファイルに保存しようとしたときに発生する例外を引き起こします。

Bitmap.LockBits() は、ピクセル データを MMF から、要求されたピクセル形式を持つメモリ内の領域にマップする別のバッファーを作成します。これで、ファイル内の形式から独立した明確に定義された形式のデータが得られました。UnlockBits() を呼び出すと、変更されたデータがあればそれが書き戻されます。ファイルからのデータが変更されたピクセルと再結合される正確な方法は指定されておらず、コーデックに大きく依存する可能性があります。

他の方法でビットマップを使用すると、まったく同じロックが発生しますが、目に見えません。Graphics.DrawImage() で画像を描画するときのように。Bitmap.GetPixel() を使用すると悪名高いです。これまでに推測できたように、ロック呼び出しでピクセル データを変換するには、かなりの量のオーバーヘッドが伴います。GetPixel() が非常に遅いのは、一度だけではなくビットマップ内のすべてのピクセルに対して行うためです。 DrawImage と LockBits() が行います。

また、オーバーヘッドの量は、画像ファイル形式、オンザフライでピクセル データをデコードする費用、デコーダによって行われるキャッシュの量、ファイルのピクセル形式とLockBits() で要求するピクセル形式。ここでは、予測可能なパフォーマンスの推測を行うにはあまりにも多くのことが行われているため、プロファイルを作成する必要があります。

于 2012-11-21T15:36:30.710 に答える
3

ビットマップは非公開の方法で保存されており、プラットフォームは実際のビットマップ データ メモリにアクセスすることを望んでおらず、lock() を使用してメモリ内にコピーを作成する必要があります。

これだと思います。ビットマップは GDI に格納され、 への呼び出しはすべて inへGetPixel()の呼び出しになります。GdipBitmapGetPixel()gdiplus.dll

Bitmap.LockBits()GDIを呼び出すBitmap::Lockbitsは、指定されたイメージの GDI によって保持されているすべてのピクセルを、管理BitmapData対象オブジェクトとして一度に返します。

のドキュメントは次のようにBitmap::Lockbits述べています。

このビットマップの四角形の部分をロックし、指定された形式でピクセル データを読み書きするために使用できる一時バッファを提供します。Bitmap::UnlockBits を呼び出すと、バッファに書き込むピクセル データが Bitmap オブジェクトにコピーされます。

GDIのドキュメントでは、「生の」ビットマップにアクセスする他の方法を見つけることができないため、これはGDIの設計方法によるものだと思います(おそらく、GDIがビットマップを(ビデオ?)メモリに保存するデバイス依存の方法のためですか?) 、したがって、「生の」ビットマップデータを操作したい場合は呼び出す必要があります。LockBits

于 2012-11-21T14:34:49.527 に答える
1

プラットフォームが単純にビットマップの最初のピクセルへのポインターを返して、ピクセルに直接アクセスできないのはなぜですか?

アイデア: すべての画像データ (「ピクセル」) は、(CPU のメモリではなく) ビデオ カードのメモリに保存できます。そのため、CPU/アプリケーションから画像データに直接アクセスすることはありません。結果として、要求によって CPU から画像データへのそのようなアクセスを取得する特別な方法が存在するはずです。のようにLockBits/UnockBits

于 2012-11-21T14:48:12.043 に答える