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

opencvを用いて、カメラから静止画を一定間隔で保存しようとしています。
プログラムを書いてみたのですが、cキーを押しても保存できません。
アドバイスや改善点、新しいプログラムを教えていただけたらと思います。
以下にプログラムを示します。よろしくお願いします。

// メインループ
// 画像表示と保存
int bSelf = 0;
int nCnt = 0;
while ( 1 )
{
// カメラからの入力画像1フレームをframeImageに格納する
frameImage = cvQueryFrame( capture );
printf("フレームの問い合わせ\n");

// 画像を表示する
cvShowImage( windowNameCapture, frameImage );
printf("フレームの描画中\n");

// 'q'キーが入力されたらループを抜ける
key = cvWaitKey( 1 );
if ( key == 'q' )
{
printf("終了します\n");
break;
}

// 'c'キーが入力されったら画像を保存する
else if(key=='c')
{
// フラグ更新
bSelf = ( bSelf == 0 );
nCnt = 0;
}

if ( bSelf && key == 0 )
{
nCnt++;

if ( nCnt >= 1000 )
{    
sprintf_s(str,"testmovie%4d.bmp",counter++);
cvSaveImage(str,frameImage);
printf("%s\n",str);

// 次回のためにカウンタを初期化
nCnt = 0;
}
}
// キャプチャ解放
cvReleaseCapture( &capture );
// ウィンドウ破棄
cvDestroyWindow( windowNameCapture );

return 0;
}

質問者からの補足コメント

  • beforekeyを定義しようしてるんですが、初期化されていませんとなります。
    自分の知識不足だとは思いますが、
    int beforekey を定義するのでは間違いなのでしょうか?

    No.6の回答に寄せられた補足コメントです。 補足日時:2016/06/22 11:14

A 回答 (9件)

>しかし、保存することはできませんでした。



関数仕様はちゃんし確認しないとダメですな……。
http://opencv.jp/opencv-1.0.0/document/opencvref …
http://bicycle.life.coocan.jp/takamints/index.ph …

というわけで、タイムアウト(キー未入力)はkey == -1で判定する必要があります。

>aを押しながらcを押すと撮影開始となるように変更するには
>どのようにしたらよいのでしょうか?

複数のキー押下を検出できない…んじゃないですかね。
SHIFTキーやCtrlキー、Altキーとの複合の場合に検出できるのかは…どうなんだろう?
「cvWaitKey Ctrl」とかで検索するとなにか見つかりますかねぇ。
    • good
    • 0
この回答へのお礼

ありがとうございます。

なかなかうまくいかないので、勉強を続けたいと思います。

お礼日時:2016/06/23 14:15

>違いがよくわかりません、keyが定義された次の文で定義したのですが、



変数宣言時に0で初期化しておく。という対処で警告は消えるかと。
    • good
    • 0
この回答へのお礼

警告を消すことはできました。ありがとうございます。

しかし、保存することはできませんでした。
aを押しながらcを押すと撮影開始となるように変更するには
どのようにしたらよいのでしょうか?

お礼日時:2016/06/23 12:05

>beforekeyを定義しようしてるんですが、初期化されていませんとなります。



エラーなのか警告なのかどちらでしょう?

>int beforekey を定義するのでは間違いなのでしょうか?

keyが定義されている箇所に定義です。
# 定義っていうか変数宣言…ですな。
初期化されていない(かも知れない)keyを参照している。とか警告が出るかも知れませんが。
    • good
    • 0
この回答へのお礼

警告がでました。

違いがよくわかりません、keyが定義された次の文で定義したのですが、

お礼日時:2016/06/22 18:35

>例えば1秒を10秒に変更しようとすると、



if ( nCnt >= 1000 )
が1000ms以上という判定なので、ここの値を修正してください。
ただし、先の回答通り1000msになるとは保証できません。
# PCのスペック次第でしょうかねぇ…。

>この部分に
>beforekey = key;
>key = cvWaitKey( 1 );
>を追加するのがベストなのでしょうか?

元々の
key = cvWaitKey( 1 );
がある行の前に
beforekey = key;
を挿入です。
当たり前ですが変数の型はよろしく処理してください。

で、その部分は「1秒を10秒に変更」とはなんの関係もありません。
キーの押下と解放で正しく状態を変更できるか。
と、1秒を意味(したい)カウンタの値。
は別です。(変更された状態によってカウントするかどうかの挙動は変わりますけど。)


カウンタでやるのではなく、timeGettime()でミリ秒取得して比較…の方がズレが出にくいと思いますけどね。
あらかじめマルチメディアタイマの制度を変更するのと、ミリ秒取得のオーバーフローに注意は必要ですが。
# Windowsの49.7日問題で検索すると出てくるかな?
この回答への補足あり
    • good
    • 0
この回答へのお礼

詳しく、親切にありがとうございます。
ここからは自力で調整していきたいと思います。

また、わからないことがあると聞くかもしれませんがよろしくお願いします。

お礼日時:2016/06/21 22:53

コピペでミスした。


>・ループ3回目
>'c'キー離しました。(2msで離すのは難しいかもしれんが)
4回目ね。
    • good
    • 0
この回答へのお礼

大変わかりやすくありがとうございます!
ミスの原因をわかりやすく伝えてくださりありがとうございます。
ミスの原因がわかりました

まだ余力があれば協力してもらいたいのですが、

例えば1秒を10秒に変更しようとすると、
bSelf = ( bSelf == 0 );
nCnt = 0;
}

if ( bSelf && key == 0 )
{
nCnt++;

if ( nCnt >= 1000 )
{    
sprintf_s(str,"testmovie%4d.bmp",counter++);
cvSaveImage(str,frameImage);
printf("%s\n",str);


この部分に
beforekey = key;
key = cvWaitKey( 1 );
を追加するのがベストなのでしょうか?

あまりにも操作が面倒くさいプログラムだと気づきまして…

ボタンを押しただけで、10秒おきに撮影は無理なのでしょうか?

お礼日時:2016/06/21 22:16

>if ( bSelf && key == 0 )


>この部分をどれだけ検索してもわからなくて、

if ( bSelf != 0 && key == 0 )
だったら判りますか?


bSelf = ( bSelf == 0 );
は、実行するたびに
・bSelfが0だったらbSelfを真(非0)にする。
・bSelfが0じゃなかったらbSelfを偽(0)にする。
という動作になります。



説明を簡単にするために
>while ( 1 )
>{
> // カメラからの入力画像1フレームをframeImageに格納する
   :
>}
>// キャプチャ解放

のループは1回回すのに1ms未満で終わるもの…とします。
cvQueryFrame()やprintf()、cvShowImage()も面倒なので説明から省きます。

・ループ1回目
なにもキーが押されていないので
>key = cvWaitKey( 1 );
で1ms待ってkeyには0が入ります。
>if ( key == 'q' )
'q'じゃないのでスルー。
>else if(key=='c')
'c'でもないのでスルー。
>if ( bSelf && key == 0 )
keyは0だけどbSelfが0なのでスルー…ということで2回目へ。

・ループ2回目
'c'キーを押下。
>key = cvWaitKey( 1 );
で押下を検出してkeyに'c'が入る。
>if ( key == 'q' )
'q'じゃないのでスルー。
>else if(key=='c')
'c'なので条件一致。
>bSelf = ( bSelf == 0 );
先の説明通りbSelfに真(非0)を設定。
>nCnt = 0;
そのままnCntに0設定。
>if ( bSelf && key == 0 )
bSelfが非0だけどkeyは0ではないのでスルー…ということで3回目へ。

・ループ3回目
'c'キーは押下状態のまま。(前回のループから1ms経過してないからね)
>key = cvWaitKey( 1 );
で押下を検出してkeyに'c'が入る。
>if ( key == 'q' )
'q'じゃないのでスルー。
>else if(key=='c')
'c'なので条件一致。
>bSelf = ( bSelf == 0 );
先の説明通りbSelfに偽(0)を設定。
>nCnt = 0;
そのままnCntに0設定。
>if ( bSelf && key == 0 )
bSelfが0なのでスルー…ということで4回目へ。

・ループ3回目
'c'キー離しました。(2msで離すのは難しいかもしれんが)
>key = cvWaitKey( 1 );
で1ms待ってkeyには0が入ります。
>if ( key == 'q' )
'q'じゃないのでスルー。
>else if(key=='c')
'c'でもないのでスルー。
>if ( bSelf && key == 0 )
keyは0だけどbSelfが0なのでスルー…ということで次のループへ。
あれれ?
'c'キー押して離したのにキャプチャするルートに入ってくれねぇです。
バグじゃね?
 いいえ、『書かれたコードに従っている』ので間違っていません。
 というワケで設計ミスです。


'c'キー押下を検出している間、bSelfはおおよそ1ms単位で真(非0)と偽(0)に変化しているので
'c'キーを離すタイミングでキャプチャの処理に入ることができます。
確率50%のルーレット。(たたしキャプチャが実行される(結果がわかる)のは1000ms後)

bSelfは'c'を押して『離したら』状態が変化する。
というように処理しないと、
・キャプチャ動作していないときに'c'を押して(離したら)キャプチャ処理開始。
・キャプチャ動作しているときにに'c'を押して(離したら)キャプチャ動作中止。
になりません。

方法はいくつかありますが…
beforekey = key;
key = cvWaitKey( 1 );
として1つ前のキーの状態を記憶するようにして、
else if(beforekey=='c' && key == 0)
として、『1回前のループの時に'c'キー押下を検出して、今回は検出できなかった場合』として判定する。
ってところでしょうかね。
ただし、コレでもダメな場合があるのでご注意を。
# 'c'キー押したまま'a'キー押して、'c'キー離す。とか……。


んで……実際のところは
cvQueryFrame( capture );
やら
printf();
やら
cvShowImage( windowNameCapture, frameImage );
などの諸々の処理の合計が1ms以内に終わることはまずないでしょうから、
>nCnt++;
も1ms間隔では実行されないでしょう。
よって、
>cvSaveImage(str,frameImage);
が1秒間隔で…ということもない。かと。
# ストレージへの書き込みはそれなりに時間がかかる。ライトキャッシュに突っ込むだけならまだ軽いとはいえ。
    • good
    • 0

>bselfがなにかもわからないような初心者には難しいことでしょうか?



元にしたコードのどこに問題があるのか把握できない。
という状態で改造しようとするのは無理でしょう。

>この部分をなくしてしまっても問題ないのでしょうか?

目の前ある時限爆弾を解除して、目覚まし時計だけ利用したい。
って状況で、いきなり配線を切ってみますか?
まぁこのコードで削除したところで死にはしませんが。
# ある意味で空き容量は死ぬかも知れんが。

>教えていただけたらと思います。

出先…というか帰宅途中なのでスマホで細かく回答する気にはなりません。
自宅着いて落ち着いたあとで余力があれば…になるでしょうね。
# 早くて21時過ぎでしょうかねぇ。真っ直ぐ帰宅するわけでもないですし。

その前に他の人から回答付くかもしれませんが。

ちなみにWindowsの挙動の関係で『1秒後に1秒毎』は保証できませんよ。
現状のコードを修正しても誤差が出るはずです。
    • good
    • 0
この回答へのお礼

申し訳ございません。
if ( bSelf && key == 0 )
この部分をどれだけ検索してもわからなくて、

全ての部分をなくすわけではなく変更するという意味です。
timeGettimeを用いたりしてやってみたのですが、やはり保存が出来なく、

私も勉強しているのですが、余力があればお手伝いしてもらいたいと思います。

ありがとうございます。

お礼日時:2016/06/21 19:22

>こちらのプログラムも先人のを参考に作りました。



ここの過去のやつですかね。
知恵袋にも似たやつありましたけど。


>こちらの部分ですが、調べてみてもよくわかりません。

printf()でbSelfの値を表示するようにして試してください。
コードの意図としては「cキーを押して、離してから1秒後に1秒毎にキャプチャ画像を保存。もう一度cキーを押して離したら保存を終了」としたかったんだろうな…とは思いますが。
もちろん、そういう風には動きません。

ここの過去の質問ではその部分が解決しないまま終わったようですが。
    • good
    • 0
この回答へのお礼

そのとおりです。

bselfがなにかもわからないような初心者には難しいことでしょうか?

私としては、cキーを押して離してから1秒毎にに保存されるものを作りたいのですが、
// フラグ更新
bSelf = ( bSelf == 0 );
nCnt = 0;
}

if ( bSelf && key == 0 )
{
nCnt++;

この部分をなくしてしまっても問題ないのでしょうか?

教えていただけたらと思います。

お礼日時:2016/06/21 18:21

opencv使ったことありませんけど……



>// 'c'キーが入力されったら画像を保存する
>else if(key=='c')
>{
>// フラグ更新
>bSelf = ( bSelf == 0 );
>nCnt = 0;
>}

'c'キーを「押してから離すまで」にbSelfがどういう遷移をするか確認してみてはどうでしょう?


「'c'キーが押されている間」、bSelfが0と1を繰り返しているんじゃないかと思いますが…。
離したタイミングでbSelfが0だったら
>if ( bSelf && key == 0 )
の判定はどうなりますかね?
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。

すいませんが、プログラム初心者なためよくわかりません。
こちらのプログラムも先人のを参考に作りました。

>// 'c'キーが入力されったら画像を保存する
>else if(key=='c')
>{
>// フラグ更新
>bSelf = ( bSelf == 0 );
>nCnt = 0;
>}

こちらの部分ですが、調べてみてもよくわかりません。

図々しいですが、詳しく教えていただけたらと思います。

お礼日時:2016/06/21 17:28

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