私のプログラムでは、いくつかの画像を読み込み、そこからいくつかの特徴を抽出し、cv::Mat
を使ってこれらの特徴を保存します。私はcv::Mat
が約720Mbであるサイズ(行x cols)700.000 x 256であると知っているイメージの数に基づいています。しかし、私が約400.000 x 256(400Mb)のプログラムを実行して、それを追加しようとすると、単に致命的なエラーでクラッシュします。誰も確かに400Mbがcv::Mat
の記憶容量の限界であることを確認できますか?より多くの問題をチェックする必要がありますか?この問題を克服する方法はありますか?C++ OpenCVの最大記憶容量
答えて
push_back
を使用して、ソースコードを掘る:
、新しい要素のための十分なスペースがあるかどうかではない場合、それは/ ための空間(current_size * 3 + 1)を用いて、マトリックスを再割り当てチェック2(see here)。あなたの例では、約400,000 * 256(合計102,400,000要素)で別の割り当てを試みるので、307,200,001/2 = 153,600,000要素の領域を割り当てようとします。しかし、これを移動するためには、新しい領域を割り当てる必要があり、その後matrix.cppからデータ
をコピーします。だから、
Mat m(dims, size.p, type());
size.p[0] = r;
if(r > 0)
{
Mat mpart = m.rowRange(0, r);
copyTo(mpart);
}
*this = m;
、本質的に:
- はデフォルトを使用して、新しい行列を割り当て新しく作成されたすべての要素のコンストラクタ
- データをコピーして古いデータを削除します。
- この行列の新しいヘッダーを作成します。十分な列あなたのケースでは、それは(60万+40万)のための十分なスペースを必要とする、という意味(旧割り当てられたメモリを解放する)新たに割り当てられたデータへ
- ポイントこの要素
* 256 - データの1ギガバイト4バイトの整数を使用します。また、1行の補助行列を作成します。この場合は600,000列になり、余分な2,400,000バイトを占めます。
したがって、600,000列に達すると、900,000x256要素(900Mb)+ 600,000x256要素(600Mb)+ 600,000(〜3.4Mb)を割り当てようとします。したがって、(push_backを使用して)このように割り当てるだけで、いくつかの再割り当てが行われます。
他の言葉:マトリックスのおおよそのサイズを知っているので、reserve
を使用する必要があります。数倍高速です(再割り当てやコピーを避ける)。
また、回避策として、転置された行列に挿入してから、処理が完了した後に再度転置することもできます。
この質問にはmalloc
/memcpy
の代わりにrealloc
を使用しないでください。
以下のようにマトリックスを作成しました。約700 MBのCV_8UC4を使用しました。まったく問題ありません。だから、400Mbは限界ではありません。 700Mbは制限ではありません。 2倍(1400000行、1.4Gb)で試してみましたが、それでも限界はありませんでした(私のデフォルト画像ビューアでは結果のBMPファイルを表示できませんでした)。この問題を克服するための
const unsigned int N_rows = 700000;
const unsigned int N_cols = 256;
cv::Mat m(N_rows, N_cols, CV_8UC4);
for (int r = 0; r < m.rows; ++r)
{
for (int c = 0; c < m.cols; ++c)
{
m.data[(r*N_cols + c) * 4] = c % 256;
}
}
cv::imwrite("test.bmp", m);
可能な方法:
- を確認するために、多分少し余分に、冒頭で
cv::Mat
に十分なスペースを割り当てます。再割り当てによって問題が発生した場合は、これが役立ちます。 - あなたのアプリケーションが32ビットである場合、あなたのコメントが示唆しているように、64ビットに変換してメモリー制限を増やしてください。
- 32ビットアプリケーションでも、720Mbは問題ではありません。しかし、おそらくあなたのアプリケーションは他のものにもっと多くのメモリを使います。そうであれば、イメージを別のプロセスに移動して、別個の2Gbを取得することができます。しかし、プロセス間通信は苦痛です。
- まだメモリに収まらないファイルを扱う必要がある場合は、メモリマップされたファイルを調べてください。OpenCVには少なくともいくつかのサポートがありますが、それ以上は使用できません。
- 必要なものに応じて、小さな行列のコレクションを使用して、読み書き/分割/結合します。
cv::Mat
のサイズには厳密な制限はありません。利用可能な限りメモリを割り当てることができます。
ここには、cv::Mat::push_back
を何度も実行しているときにデータポインタに何が起こるかを示す小さなプログラムがあります。 rows
とcols
の値で再生すると、最終的にメモリ不足の例外がスローされる前に、1つまたは複数の値がa.data
として出力される可能性があります。
#include <opencv2/opencv.hpp>
int main()
{
int rows = 1, cols = 10000;
cv::Mat a(rows, cols, CV_8UC1);
while(1) {
a.push_back(cv::Mat(1, cols, CV_8UC1));
std::cout << (size_t) a.data << std::endl;
}
}
実際には、上記のコードが行と列のさまざまな値に対して何を行うかに関するアロケータに依存します。したがって、a
の小さい初期サイズと大きい初期サイズを考慮する必要があります。
C++ 11 std::vector
と同様に、cv::Mat
の要素は連続しています。基盤となるデータへのアクセスは、cv::Mat::data
メンバーから取得できます。 std::vector::push_back
またはcv::Mat::push_back
を継続的に呼び出すと、基になるメモリが再割り当てされることがあります。この場合、メモリは新しいアドレスに移動されなければならず、古いメモリから新しいメモリに移動するにはメモリの約2倍の量が必要になることがあります。
さて、私は 'cv :: Mat :: push_back'を呼び出すたびに1行を追加します。これは合計700.000コールです。私は 'cv :: Mat :: push_back'の総呼び出しを減らす必要があると思います。 – DimChtz
私が正しく覚えていれば、動的成長を可能にする連続した構造のためのかなり一般的なメモリ割り当て戦略は、スペースを使い果たしたときに前のサイズの2倍を割り当てることです。これはおそらく、移動するのに要する時間のおよそ3分の1を意味します。古いサイズの2倍の新しいメモリブロック+古いメモリブロック。データがコピーされるまで削除できません。 – Headcrab
@Headcrab 'cv :: Mat'と連続していないデータを使用することはできますか? – DimChtz
- 1. SQLiteデータベースの最大記憶容量
- 2. データベースセッションの記憶容量の制限
- 3. tfs2015:ユーザー容量データベース記憶域
- 4. STM32 USBデバイスライブラリを使用する大容量記憶装置としてのフラッシュメモリ
- 5. 's'の記憶容量がわからない+ポインタへのポインタ
- 6. MongoDBの記憶容量が不足しています。32ビット
- 7. imap-send.c:865:エラー: 'hamc'の記憶容量がわからない
- 8. 'var'の記憶容量はわかりません
- 9. EVP_MD_CTX "エラー: 'ctx'の記憶容量がわからない"
- 10. 最大SharePointコンテンツDB容量
- 11. 大容量の大容量ファイル
- 12. Androidアプリケーションが高記憶容量を消費しています
- 13. C++ブースト大容量ストレージ
- 14. IIS6 ASP.NET 2.0アプリケーションキャッシュ - 大量データ用のデータ記憶域オプションとパフォーマンス
- 15. イベントと最大容量のFacebookページ
- 16. NodeJS + Electron - 大容量ファイルの最適化
- 17. Cでの大容量メモリの問題
- 18. 大容量アレイでのC++パフォーマンス
- 19. Cセグメンテーションフォールトは、大容量のファイル
- 20. CordovaのiOSでアプリの記憶容量がなくなりました。
- 21. C#ソケットサーバー - 最大容量と一般的な質問
- 22. valgrindの大容量でC++アプリケーションの最大メモリ使用量(スタックとヒープ)を測定する
- 23. okhttp3大容量ファイルのOutOfMemoryError
- 24. Railsは大容量のファイル
- 25. 大容量データの問題
- 26. 大容量のPythonバックグラウンドジョブ
- 27. 大容量シングルレコードインサートのためのMSSQLの最適化
- 28. C#のスタック容量
- 29. 大容量/低速接続での大容量ファイルのアップロード方法
- 30. 最大流量
これはありません。利用可能なメモリを割り当てることができるはずです。より多くの問題を確認する必要があります。 –
@RobertPrévostしかし、 'cv :: Mat :: push_back()'はシステムに十分なRAMがある間に "outOfMemory"エラー例外をスローします。 – DimChtz
'cv :: Mat :: push_back'はおそらく少なくとも同じサイズの別の行列を割り当てます。データを2倍にするのに十分なスペースがありますか? –