0

OpenCV 用の Java インターフェイスである JavaCV を使用して OMR (Optical Mark Recognition) アプリケーションを開発しています。アプリケーションは 200 個の画像に対して正常に動作しますが、その後、コード内の IplImage にメモリを割り当てることができません。imgx のクローンを作成しようとすると、割り当てエラーが発生します。それをimgxc1に割り当てます。プログラムによる修正を提案してください。ヒープサイズを増やすことは一時的な解決策のようですか?

初期化コードは次のとおりです(例外が発生する場所):

protected boolean init () throws UnableToLoadImage{
    imgx = new IplImage();
    imgxc1 = new IplImage();
    imgxd1 = new IplImage();
    imgx = cvLoadImage(path+DR+filename);
    if(imgx == null)throw new UnableToLoadImage(path+DR+filename);
    //cvSaveImage("debug/"+filename, imgx);
    imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());
    imgxc1 = imgx.clone();//error comes here
    imgxd1 = cvCreateImage(cvGetSize(imgx), IPL_DEPTH_8U, 1);
    cvCvtColor(imgxc1, imgxd1, CV_BGR2GRAY);
    return (imgx != null && imgxc1 != null && imgxd1 != null)?true:false;
}

クリーンアップコードは次のとおりです。

public void release() {
    if(imgx != null){

        imgx.release();
        imgxc1.release();
        imgxd1.release();

        cvReleaseImage(imgx);
        cvReleaseImage(imgxc1);
        cvReleaseImage(imgxd1);
    }

}

スタックトレース:

OpenCV Error: Insufficient memory (Failed to allocate 6454368 bytes) in cv::OutOfMemoryError, file ..\..\..\..\opencv\modules\core\src\alloc.cpp, line 52

at org.bytedeco.javacpp.opencv_core.cvCloneImage(Native Method)
at org.bytedeco.javacpp.helper.opencv_core$AbstractIplImage.clone(opencv_core.java:1005)
at com.omr.app.OmrModel.init(OmrModel.java:200)
at com.omr.app.OmrController$2.doInBackground(OmrController.java:328)
at com.omr.app.OmrController$2.doInBackground(OmrController.java:1)
at javax.swing.SwingWorker$1.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
4

1 に答える 1

3

あなたのコードは奇妙に見えます。オブジェクトを変数に割り当てていIplImageますが、それらを即座に上書きするだけです。次の場合、少なくとも 1 つのおそらくネイティブ リソースもリークしています。

imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());
imgxc1 = imgx.clone();//error comes here

で作成された元のimgxc1オブジェクトにはcvCreateImage参照がありませんが、リソースを解放していません。

Java で参照がどのように機能するかが不明な場合は、作業を続行する前に、その作業を行うことをお勧めします。冗長な二重代入行がなくなり、コードもより明確になります。

編集:私はすでにこれに時間を浪費しているので、init()行ごとに見ていきましょう.

protected boolean init () throws UnableToLoadImage{
    imgx = new IplImage();    // Create a new IplImage() even though we won't use it

    imgxc1 = new IplImage();  // Same here. Just food for the garbage collector

    imgxd1 = new IplImage();  // Third completely unnecessary object creation

    imgx = cvLoadImage(path+DR+filename);  // Load an image, the previously created object in imgx is now GC food

    if(imgx == null)throw new UnableToLoadImage(path+DR+filename);
    //cvSaveImage("debug/"+filename, imgx);

    imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());  // Create an image with native resources, previous object is GC food

    imgxc1 = imgx.clone();    // Third time assignment to imgxc1, previous object isn't GC food since it holds native resources
    imgxd1 = cvCreateImage(cvGetSize(imgx), IPL_DEPTH_8U, 1);  // The first proper use of cvCreateImage
    cvCvtColor(imgxc1, imgxd1, CV_BGR2GRAY);  // Presumably ok
    return (imgx != null && imgxc1 != null && imgxd1 != null)?true:false;  // Doesn't need the ternary operator at all
}

このコードは Java の大きな誤解を示していますが、ネイティブ リソースが含まれていなければ、ガベージ コレクターによって処理される余分なオブジェクトが作成されるだけです。

于 2015-10-22T09:09:11.567 に答える