usao さんの説明をスルーしてしまうより、どの部分が分からなかったのかを書いていただいた方が建設的な議論ができると思いますが・・。
さて、質問者さんがどういうコードを書いているのか分からないので、以下のコードで説明します。
コード:
#include <opencv2/highgui.hpp>
int main(int argc, char *argv[]) {
if (argc >= 2) {
auto image = cv::imread(argv[1], cv::IMREAD_COLOR);
cv::namedWindow("Display window", cv::WINDOW_AUTOSIZE);
cv::imshow("Display window", image);
cv::waitKey(0);
}
return 0;
}
cv::namedWindow を呼ぶと、空のウィンドウを作って、それを表示します。cv::imshow は、ウィンドウ上のカスタム コントロールに画像のビットマップデータを紐づけますが、実際の描画は行ないません。
したがって、上記プログラムで waitKey を呼び出す処理がない場合、空のウィンドウが一瞬だけ表示されて、そのままプログラムが終了してしまいます。
cv::waitKey は、ユーザーからのキー入力を取得する関数ですが、実際にはメッセージループの役割を持っています。
ウィンドウ ベースのプログラムの場合、ウィンドウを表示してから、何らかの方法でマウス入力やキー入力などを待ちながら、プログラムを実行し続けなければなりません。そのための仕組みがメッセージループです。
(入力を受け付けないループが、いわゆるフリーズだとかハングアップと言われる現象です。)
ループの部分は、OpenCV のコードを実際に見た方が理解が早いかもしれません。Windows で cv::waitKey を呼ぶと、以下の cvWaitKey が実行されます。
https://github.com/opencv/opencv/blob/m ... .cpp#L1920
見て分かるように二重の for ループがあります。内側は、複数のウィンドウを順に処理するためのループで、外側がメッセージ ループです。
最初の方で、GetMessage という API を使って、ウィンドウに送られてきたメッセージを読み出します。
キー入力を受け取ったときにキーの種類を返すため、GetMessage で受け取ったメッセージが条件 (メッセージの種類が WM_KEYDOWN、WM_SYSKEYDOWN などなど) を満たしている場合、ループから抜けるようになっているのが分かると思います。条件を満たさないメッセージの場合は、DispatchMessage を使って、メッセージをウィンドウプロシージャに送り、ウィンドウの既定の動作をするようにしています。
cv::imshow は、データを紐づけるだけで描画は行ないませんでした。描画が行われるタイミングは、カスタム コントロールに WM_PAINT メッセージが送られてきたときです。描画の処理は、同じファイルの HighGUIProc という関数にあります。
https://github.com/opencv/opencv/blob/m ... .cpp#L1629
したがって画像を表示するためには、少なくとも一回は WM_PAINT を処理する必要があり、これが、cv::waitKey を呼び出さないと画像が表示されない理由でもあります。
へえ? さんが書きました:
MS visual studio 2015のdebug状態で逐文実行する場合、
wait()がなければ、だめで、wait()を実行してから、
OpenCVによる画面に出されているimage表示windowをモウスでアクティブさせて、
何かキーを押せば、imageがきちんとOpenCVが出してくれたwindowに表示できて、
そして、次のC言語のセンテンスに行きます。
このような動きを論理的・理論的に解釈できる方、いらっしゃらないでしょうか。
端的に回答するならば、cv::waitKey がそのように実装されているから、になるでしょうか。「そのように」とは、メッセージループを実行してウィンドウに送られてくるメッセージを順次処理しながら、もしキー入力があれば、ループを抜けて関数が戻り値を返すように、という意味です。
画像表示についても繰り返しになりますが、ループが処理するメッセージには WM_PAINT も含まれており、OpenCV は、このメッセージを処理するときに初めて画像を描画するので、cv::waitKey を実行しないと画像が見えません。
余談ですが、例えば以下のようにループを自分で書いて画像を表示することはできます。
コード:
#include <opencv2/highgui.hpp>
#include <windows.h>
int main(int argc, char *argv[]) {
if (argc >= 2) {
auto image = cv::imread(argv[1], cv::IMREAD_COLOR);
cv::namedWindow("Display window", cv::WINDOW_AUTOSIZE);
cv::imshow("Display window", image);
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0) > 0) {
if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
ただし上記例では、ウィンドウの右上の×ボタンがクリックされたことをメッセージから判断できず、キー入力以外ではプログラムが終了しません。
OpenCV 内部では、作成されたウィンドウをリンクトリストとしてグローバル変数の hg_windows で管理しているみたいですが、外部からアクセスする真っ当な方法がないので、真面目にやるなら何か別の方法を見つけないといけません。