プロが教えるわが家の防犯対策術!

OpenCVで画像判定プログラムを作成しています。
大まかなプログラムは出来、現在細かなデバックを行っています。
現在、問題として、メモリーリークが発生しているみたいです。

ファイルを読み込む時、
IplImage *sourceImage;
sourceImage=cvLoadImage("image/lena.jpg",CV_LOAD_IMAGE_ANYDEPTH|CV_LOAD_IMAGE_ANYCOLOR );
cvReleaseImage( &sourceImage );

としますが、これは読み込んだバッファー等の情報がsourceImageに書き込まれ、最後にcvReleaseImage( &sourceImage );を実行する事により、バッファー等のファイルを読み込む為に確保されだ領域が削除されると理解しています。

今までの私のC言語でのプログラミングの経験では、先ずバッファーを確保し、そこにファイルを読み込むと言う事を行って来ましたので、ファイルの次のレコードを読み込む場合はそのバッファーに上書きされて読む事ができました。

OpenCVでは上記sourceImageにバッファー等の情報が渡されますが、次のレコードを読む時はどう成るのでしょうか? 又、新たなバッファー領域が確保されてその情報が渡されるのでしょうか。そうすると、cvReleaseImageでは先に読み込んだバッファーの開放が出来なく成ると思います。それとも、読み込みは同じバッファー領域にされるのでしょうか。 ただ、そうすると、2回目の読み込みは上記、sourceImageで無く、別のIplImageで作成したポインターを指定した時、両方cvReleaseImageで開放してしまうと、同じ領域を2回開放してしまう事に成ってしまいます。

今、自宅なので参照出来ませんが、何か、リセットイメージみたいなコマンドがありました。ひょっとして、次のレコードを読み込む時は毎回このリセットイメージの様なコマンドをcvLoadImageとペアで使用して、最後にcvReleaseImageで開放するのでしょうか。

質問を書いている時に、更に疑問が出て来ました。もし、リセットイメージコマンドがあるとして、これを掛けた後、データーを読み込みもせず、cvReleaseImageもかけなかった時はメモリーリークは発生するのでしょうか。

この辺の動作が分かりません、お分かりに成る方、宜しくご教授下さい。

A 回答 (2件)

cvLoadImageはIplIamge構造体の画像の幅や高さなどに値を代入に、imageDataのポインタにmallocしたポインタを代入し、このポインタの示すメモリに画像データを格納します。


そのため、cvLoadImageとcvReleaseImageは必ずペアで使います。


補足して頂いた

>IplImage に cvLoadImage されたものを、 例えば cvResetImage 見たいなコマンドでバッファークリアーをして
>再度 IplImageで作成した構造体に cvLoadImage を行える

の部分が良く分からなかったのですが、”バッファークリア”や”リセットイメージ”という処理は、メモリの解放なのか?それともメモリの初期化(全ての値を0にするなど)の事でしょうか?

ちなみに、特定の値で初期化するには、cvSetやcvZeroなどがあります。

いづれにしても、cvLoadImageで画像ファイルから画像データを取得しようとする以上、cvLoadImage内であらたにメモリを確保してしまうので、
for( int iCnt = 0; iCnt < 10; iCnt++ )
{ iplImg = cvLoadImage( "ファイル名", パラメーター );
cvReleaseImage( &iplImg );
}
のように書かないといけません。

また、OpenCVのIplImage構造体といえども、ただのC言語の構造体なので、IplImage構造体の配列にして、

IplImage* imgs[10];

for (int i = 0; i < 10; i++){
imgs[i] = cvCreateImage(cvSize(5000,5000), 8, 1);
}

for (int i = 0; i < 10; i++){
cvReleaseImage(&imgs[i]);
}

というような書き方もできます。
最後にまとめて解放できる処理があったという事ですが、ニュアンス的に似ているのは全てのウィンドウを閉じるcvDestroyAllWindowsぐらいでしょうか?
また、メモリの解放が面倒というのであれば、私はあまり使っていないのですが、OpenCV2.0から登場したcv::Matを使うのも手だと思います。
    • good
    • 0
この回答へのお礼

再度のご回答有難うございます。

全ての画像を一度に開放するのでは無く、一つ一つ処理するので、一つ前の画像の開放がどうなっているか、上書きされるのか、上書きされるとしてら、前の画像の情報は何処に行ってしまうのかと思い質問しました。
結論として、cvLoadとcvReleaseImageはペアで使わなければ行けない様なので、プログラムをみて、ペアに成っていない所を探してみます。

私の部署ではOpenCVは初めてで、相談者も居なく困っておりました。
現在作成中のプログラムは私の部門ではOpenCVの解説の役割も担う事に成りますので、コメントを多く入れていますので、この辺の関数内部の動きもコメントに書き込んで置きます。

有難うございました。

お礼日時:2011/04/05 07:19

C言語の経験があるのなら、cvLoadImageとcvReleaseImageはC言語のmallocとfreeとの関係と同じです。


cvLoadImageでは内部的には必ずmallocを行うので、cvLoadImageとcvReleaseIamgeを対で使わないとメモリリークしてしまいます。
もし、作業用のIplIamgeを確保したいのなら、cvCreateImageを使います。
これもやっぱり内部的にはmallocを行うので、使い終わったらcvReleaseIamgeが必要です。

メモリ確保をせずに画像ファイルを読み込める関数があるか?定かでないのですが、読み込むまで画像サイズの分からないファイルからデータを読み込むので、やっぱり、そういう関数は無いかも?しれません。

この回答への補足

ご回答有難うございます。

書き方が悪くて誤解を与えてしまった様ですが、メモリーを確保せずにファイルを読み込む関数は無いと思います。

IplImage に cvLoadImage されたものを、 例えば cvResetImage 見たいなコマンドでバッファークリアーをして 再度 IplImageで作成した構造体に cvLoadImage を行える様なコマンドでしたが、本日会社に行き、色々探したのですが、分かりませんでした。

本題ですが、私は複数画像取得する時に

IplImage* iplImg;

for( int iCnt = 0; iCnt < 10; iCnt++ )
{iplImg = cvLoadImage( "ファイル名", パラメーター );
}
cvReleaseImage( &iplImg );

の様にコーディングすれば良いと思っていましたが、cvLoadImageがMalloc、cvReleaseImageがFreeに相当するとすると、

IplImage* iplImg;

for( int iCnt = 0; iCnt < 10; iCnt++ )
{ iplImg = cvLoadImage( "ファイル名", パラメーター );
cvReleaseImage( &iplImg );
}
とコーディングしなければ成らないと言う事で良いと思います。
この理解でよろしいでしょうか。

因みに私が見たと思っているコマンドをcvXxxxとすると

IplImage* iplImg;

for( int iCnt = 0; iCnt < 10; iCnt++ )
{iplImg = cvLoadImage( "ファイル名", パラメーター );
cvXxxx( &iplImg );
}
cvReleaseImage( &iplImg );

とコーディングする様に書かれていた記憶があります。

ただし"ファイル名"はその都度変わるものとします。

補足日時:2011/04/04 20:06
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!