web-dev-qa-db-ja.com

OpenCV-画像表示ウィンドウを閉じる

私は画像データベースを検索するプロジェクトに取り組んでおり、いくつかのクエリ(5つのデータベース画像)の結果が見つかったら、結果を視覚的に表示したいと思います。すべての画像をメモリに保持しているわけではないので、表示するために最初に画像をロードする必要があります。

私は擬似コードで何か簡単なことを考えていました:

_for image 1..5
    load images
    display image in a window
    wait for any keypress
    close the window
_

この目的でOpenCVを使用した_C++_のコードのスニペットを次に示します。

_IplImage *img;

for (int i=0; i < 5; ++i){
    img = cvLoadImage(images[i].name.c_str(),1);
    cvShowImage(("Match" + images[i].name).c_str(), img);
    cvWaitKey(0);
    cvDestroyWindow(("Match" + images[i].name).c_str());
    // sleep(1);
    cvReleaseImage(&img);
}
_

ここで使用されるimages配列は私のコードには存在しませんが、質問のために、nameの場合、現在のプログラムの実行ポイントに関連する画像のファイル名が含まれていますメンバー。私のプロジェクトでは、イメージ名を少し異なって保存しています。

上記のコードalmostは機能します:4/5の画像を反復処理できますが、最後の画像が表示され、キーが押されると、画像がグレーになり、閉じることができません私のアプリケーションの残りをクラッシュさせることなく画像ウィンドウ。

私の最初のアイデアは、コンパイル時の最適化のため、cvReleaseImageが終了する前にcvDestroyWindowがイメージをリリースし、それが何らかの形でフリーズするというものでした。しかし、待ち時間を追加しようとしました(そのため、コードのsleep(1)行をコメントアウトしています)。

コンソールアプリケーションからこの表示機能を呼び出しています。画像がフリーズすると、コントロールがアプリケーションに戻り、使用を継続できます(ただし、画像ウィンドウはバックグラウンドでフリーズしています)。

これを修正する方法について提案をお願いできますか?

[〜#〜] edit [〜#〜]

私は質問をして以来、定期的にコンピュータービジョンとOpenCVを扱っている一部の人々と話しましたが、まだアイデアはありません。

同様の stackoverflow question を見つけましたが、まだ受け入れられている答えはありません。 Googleingは結果として同様の質問をするだけで、答えはありません。

何を試すべきか(完全な解決策でなくても)どんなアイデアでも大歓迎です。

19
penelope

テストの目的で、以下のアプリケーションは質問で述べたとおりに実行します:コマンドラインを使用して7つのイメージを1つずつロードし、表示するイメージごとに新しいウィンドウを作成します。

Linux上のOpenCV 2.3.1で問題なく動作します。

#include <cv.h>
#include <highgui.h>

#define NUM_IMGS 7

int main(int argc, char* argv[])
{
    if (argc < 8)
    {
        printf("Usage: %s <img1> <img2> <img3> <img4> <img5> <img6> <img7>\n", argv[0]);
        return -1;
    }

    // Array to store pointers for the images
    IplImage* images[NUM_IMGS] = { 0 };

    for (int i = 0; i < NUM_IMGS; i++)
    {
        // load image
        images[i] = cvLoadImage(argv[i+1], CV_LOAD_IMAGE_UNCHANGED);
        if (!images[i])
        {
            printf("!!! failed to load: %s\n", argv[i+1]);
            continue;
        }

        // display image in a window
        cvNamedWindow(argv[i+1], CV_WINDOW_AUTOSIZE); // creating a new window each time
        cvShowImage(argv[i+1], images[i]);

        // wait for keypress
        cvWaitKey(0);

        // close the window
        cvDestroyWindow(argv[i+1]);
        cvReleaseImage(&images[i]);
    }

    return 0;
}
19
karlphillip

cvDestroyWindow()通常開始のみウィンドウ破壊のかなり複雑な手順。この手順では、ウィンドウシステムとアプリケーションの間で何らかの相互作用(イベント交換)が必要です。この手順が完了するまで、ウィンドウを完全に破棄することはできません。これが、アプリケーションがGUIに関係のない何かを実行している間に、部分的に破壊されたウィンドウが表示される理由です。

イベント交換は、システムに依存した方法で実行できます。 Windowsでは、これは(直接または間接的に)GetMessageまたは_MsgWaitFor*_関数を呼び出して結果を処理することを意味します。 Unixの場合、これは(直接または間接的に)XNextEventを呼び出して結果を処理することを意味します。

OpenCVでは、このイベント交換をシステムに依存しない方法で行うことができます。これを行うには、文書化された2つの方法があります。最初はcvWaitKey()です(最後の画像を閉じた後にcvWaitKey(1)を呼び出すだけです)。 2つ目は、プログラムの開始時にcvStartWindowThread()を呼び出して、OpenCVがウィンドウを自動的に更新できるようにすることです。

これらのメソッドのうち、libcv2.1を搭載したLinuxボックスで正常に機能したのは、cvStartWindowThread()の1つだけです。


更新(cvStartWindowThread()を使用したコードスニペット)

_//gcc -std=c99 main.c -lcv -lcxcore -lhighgui
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdio.h>
#include <unistd.h>

#define NUM_IMGS 2

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        printf("Usage: %s <img1>\n", argv[0]);
        return -1;
    }

    cvStartWindowThread();

    // Array to store pointers for the images
    IplImage* images[NUM_IMGS] = { 0 };

    for (int i = 0; i < NUM_IMGS; i++)
    {
        // load image
        images[i] = cvLoadImage(argv[i+1], CV_LOAD_IMAGE_UNCHANGED);
        if (!images[i])
        {
            printf("!!! failed to load: %s\n", argv[i+1]);
            continue;
        }

        // display image in a window
        cvNamedWindow(argv[i+1], CV_WINDOW_AUTOSIZE); // creating a new window each time
        cvShowImage(argv[i+1], images[i]);

        // wait for keypress
        cvWaitKey(0);

        // close the window
        cvDestroyWindow(argv[i+1]);
        cvReleaseImage(&images[i]);
    }

    //    cvWaitKey(1);
    sleep(10);
    return 0;
}
_
5
Evgeny Kluev

各フレームでウィンドウを破棄する必要はありません。同じウィンドウ名でcvShowImage()を呼び出すだけで、現在の画像が置き換えられます。

シャットダウン時に破棄ウィンドウを呼び出すだけです。 cvCreateWindow()を使用して起動時にウィンドウを作成できますが、最初のshowWindow()呼び出しで自動的に作成されます。

2
Martin Beckett

あなたのコードでは、cvNamedWindow()を呼び出して、画像を表示する(そして破壊する)ウィンドウを作成していません。おそらく、cvShowImage()(karlphillipが his answer で示しているように)の前に、これらの呼び出しの1つをループに入れる必要があります。

ループの前に名前付きウィンドウを作成する場合:画像に重複した名前がないことを確認しましたか?破壊されたウィンドウに画像を割り当てないようにし、すでに破壊されたウィンドウを破壊しないようにするために?

cvDestroyWindow()のすべての呼び出しを省略し、代わりにcvDestroyAllWindows()の単一の呼び出しを使用すると、問題を回避できますか?

1
moooeeeep

5番目の画像が正しく読み込まれることをテストしましたか?これはどうですか?

for(...)
{
   if(!img)
       break;

   // display it
}

発生する問題は、cvShowImage()へのヌルポインターのように聞こえます。

0
Sam

すべてのOpenCV画像表示ウィンドウを閉じたい場合は、destroyAllWindows();を使用します。

0
Samer