重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

DIBからAVIを作成するプログラムを作っているんですが、作成されたAVIを再生してみると、早送りのような感じになってしまいます。
再生時間も実際の録画時間の5~7分の1くらいです。
CCDカメラで写した画像をDIBとして扱って、AVIファイルに出力するようなロジックです。

デジタル時計をCCDカメラで写して再生してみると、やはり時計が秒をうつ間隔が一定ではないんです。

画像処理プログラムを作るのは今回が初めてなので、インターネットで検索して見つけたコードを真似ただけで、理屈がわかっていません。

そのため、ロジックのどこに問題があるかわかりません。
ご存知の方、教えていただけないでしょうか?

質問が長くなってはいけませんので、プログラムの詳しいことについては、補足で回答したいと思います。

A 回答 (8件)

質問の中で「時計が秒をうつ間隔が一定ではない」というところを読み落としていました。

リアルタイムで取得した画像をAVIファイルに出力しているのですね。

その場合、その「リアルタイムでの画像取得」の取得間隔自体が一定していないことが考えられます。

画像取得の間隔が一定しない場合、その対策は3通りあります。

1つは、画像取得のたびに取得時刻を算出し、あらかじめ定めた間隔よりも短い場合は破棄、長い場合はダミーフレームをAVIに挿入し、平均のフレーム間隔が「あらかじめ定めた間隔」に一致するようにする方法。

2つ目は、こういった処理を自動的に行ってくれるDirectShowのフィルタを使って、面倒な処理を全部任せてしまうこと。

3つ目は、自分専用の独自のAVIフォーマットを作成し、そのフォーマットで可変フレーム間隔をサポートしてしまうことです。

既にDirectShowを使っているのであれば2つ目、そうでなければ1つ目が簡単です。

この回答への補足

回答ありがとうございます。

本当はDirectShowに全部任せたいのですが、使っているビデオキャプチャカードが、
ビデオキャプチャのデバイスの列挙をしても見つからない(※)ので、
カードとのインタフェースにはカードに付属しているSDKを使っています。

フレームのスナップとDIBの取得はそのSDKを使っています。
ダミーを挿入するのは難しくないですかね?
ダミーってどんなフレームでもいいんでしょうか?
「あらかじめ定めた間隔」とはどのくらいの間隔が適当でしょうか?

※CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
を実行して、pClassEnumがNULLになる。

補足日時:2005/07/24 18:28
    • good
    • 0

BITMAPINFOHEADER構造体とAVISTREAMINFO構造体の二者択一でしたら、AVISTREAMINFO構造体です。

(BITMAPINFOHEADER構造体には「時間」に関するメンバ変数はありませんので。)

ただし、AVIファイルのヘッダにはこのほかAVIMAINHEADER構造体というものがあり、ここにもフレーム間隔の情報があります。

同じAVIファイルの中でAVIMAINHEADER構造体とAVISTREAMINFO構造体に別のフレーム間隔を設定したことがないので、AVIファイル再生時に実際にはどちらが優先して使用されるのかは分かりません。

DIBに関しては、1つのDIBは要するに1コマのビットマップですので、1つの画像データのみが入ります。
    • good
    • 0
この回答へのお礼

ありがとうございました!

お礼日時:2005/07/26 00:00

別の場所でこの手の質問をするとすれば、どこでしょうね・・・どうも2chくらいしか思いつきません。



なお、どうか気を悪くしないでいただきたいのですが、私としては当初の質問である「早送りになってしまう/ロジックのどこが問題なのか」に対する回答(「出力ファイル中のフレーム間隔とフレーム数の関係のせいで早送りとなる/フレーム数調整ロジックに問題があると思われる」)として、回答No.2か、せめてNo.3まででご納得いただけることを期待しておりました。

今回の質問のようにある程度専門的な話題の場合、いったん回答者が回答を始めると他の回答者が割って入るのが難しいので、最初に回答した者の責任として回答を続けておりましたが、正直なところ場所を変えてまで続きを行うのは遠慮させていただきたいです。

(注:この回答は質問への回答となっておらず、質問者の叱責のようになっておりますため、運営スタッフにより削除される可能性があります。また、不快に思われました場合は、お手数ですが右上の「運営スタッフに連絡」を使用して削除をご依頼ください。)
    • good
    • 0
この回答へのお礼

今まで付き合っていただき、ありがとうございました。

最後にもう少しだけ教えていただきたいのですが、
「AVIのヘッダに設定するフレーム間隔」とは、BITMAPINFOHEADER構造体のメンバ変数のことでしょうか?それともAVISTREAMINFO構造体のメンバ変数のことでしょうか?
(AVIのヘッダはAVISetStreamFormatで設定しますよね?)
それと、一つのDIBに複数のフレームデータが入っていることはありえるのでしょうか?

お礼日時:2005/07/25 23:27

ダミーフレーム挿入の判断について:



AVIのヘッダに設定するフレーム間隔を仮に100msとします。またフレームレート調整ポリシーは「予定時刻よりも早く来たフレームはすべて捨てる、予定時刻よりも1フレーム分以上遅れたフレームはダミーフレームを埋める」とします。

この場合、フレーム取得時刻とAVIファイルに出力するフレームの関係は次のようになります。


最初に1枚フレームを取得します。このときの時刻が0.00秒だったとします。1枚目はそのままAVIファイルに出力します。

次のフレームを取得。時刻は0.05秒だったとします。2枚目を出力すべき時刻(0.10秒)より早いので、このフレームは捨てます。

次を取得。時刻は0.12秒だったとします。2枚目を出力すべき時刻(0.10秒)以降なので、このフレームをAVIファイルに出力します。3枚目を出力すべき時刻(0.20秒)よりは前なのでダミーフレームは出力しません。

次を取得。時刻は0.35秒だったとします。3枚目を出力すべき時刻(0.20秒)以降なので、このフレームをAVIファイルに出力します。4枚目を出力すべき時刻(0.30秒)も過ぎているので、もう1枚ダミーフレームを出力します。5枚目を出力すべき時刻(0.40秒)よりは前なので、それ以上ダミーフレームは出力しません。

次を取得。時刻は0.39秒だったとします。5枚目を出力すべき時刻(0.40秒)より早いので、このフレームは捨てます。

次を取得。時刻は0.45秒だったとします。5枚目を出力すべき時刻(0.40秒)以降なので、このフレームをAVIファイルに出力します。6枚目を出力すべき時刻(0.50秒)よりは前なのでダミーフレームは出力しません。


この例ではちょっとでも早く取得したフレームをすべて捨てていますが、実際にはある程度幅を持たせて弾性的に調整したほうがよいでしょう。その具体的な方法は説明するには長すぎるので省略します。
    • good
    • 0
この回答へのお礼

ありがとうございます。

いろいろと聞きたいことが多すぎるので、ここではなく別の方法で聞きたいのですが、何か良い方法はありますか?

MSNメッセンジャーくらいしか思いつかないんですけど。

お礼日時:2005/07/25 21:53

フィルタがGraph Editで表示されないのでは、DirectShow以外の方法でキャプチャするしかありませんね・・・(自前でフィルタを作る手もないではないですが)



録画時間と再生時間に直接の関係はありません。再生時間は単純に、ヘッダに書いてあるフレーム間隔×ファイルの中にあるフレーム数で決まるからです。

それで、フレーム数が明らかに足りないということですが、それは「間隔が開いた場合にはダミーフレームを挿入する」という方法を取ってもなお足りないということでしょうか。例えば、AVIファイルのヘッダにフレーム間隔1/30秒と設定し、10秒間に相当するはずのAVIファイルを作成しても、ファイル内のフレーム数が300フレームよりだいぶ少ないということでしょうか。

そうだとすれば、フレーム間隔の認識あるいはダミーフレーム挿入のロジックが誤っていると思われます。

フレーム取得時の時刻はちゃんと毎回取得しているでしょうか。ダミーフレームを挿入するかどうかの判断はフレーム間の時間間隔ではなく「これまで出力したフレーム数と現在時刻」で判断しているでしょうか。


「フレーム数が足りない」の意味が「カメラから取得できるフレームの数が少ない」という意味合いでしたら、AVIファイル作成処理を云々する前に、まずカメラから取得できるフレームレートを測っておいたほうがよいでしょう。

プログラム上全速力で例えば100フレームを取得し、その時間を測ります。ファイル出力は必要ありません。ただフレームを取得し、それに要した時間をフレーム数で割って出力するだけです。(あるいは一定時間内に取得できたフレーム数から計算してもいいでしょう。)

仮にこの数字が毎秒10フレームとなったとすれば、そのカメラとAPIの組み合わせでは、どんなにがんばっても毎秒10フレームを超えるフレーム数のAVIファイルは(ダミーフレームを挿入しない限り)作成できないということになります。

この回答への補足

>それは「間隔が開いた場合にはダミーフレームを挿入する」という方法を取ってもなお足りないということでしょうか。
そうです。
約30秒間録画したときのフレーム数(AVIStreamWriteを呼び出した回数)は、100~160でした。

>フレーム取得時の時刻はちゃんと毎回取得しているでしょうか。ダミーフレームを挿入するかどうかの判断はフレーム間の時間間隔ではなく「これまで出力したフレーム数と現在時刻」で判断しているでしょうか。

補足でも触れましたが、AVIStreamWriteを呼び出した後にGetTickCountを実行(A)、その次にAVIStreamWriteを呼び出す前にGetTickCountを実行(B)、B-Aで時間間隔を算出しています。
どうやら、間違っているようですね。

ビデオキャプチャカードの仕様によれば、フレームレートは29.9くらいだそうです。

基本的なことを聞くようで申し訳ないのですが、そもそもキャプチャカードのフレームレートというのは何を意味するのでしょうか?
1秒間に何枚のフレームがキャプチャできるかを意味すると思って良いでしょうか?
それにしても、いくら多くキャプチャできても、AVIに出力しなければ、何の意味もないと思うんですが。

AVIStreamWriteでDIBから1フレームしか書き込むようにしか作っていないので、「カメラから取得できるフレームの数が少ない?」という件については、よく意味がわかりません。
取得したDIBで数枚のフレームをAVIに出力可能なんでしょうか?

補足日時:2005/07/25 20:41
    • good
    • 0

Video for Windowsのキャプチャデバイスも、確かカテゴリCLSID_VideoInputDeviceCategoryで列挙されたかと思います。

Graph Editでは列挙されませんでしたか?(Graph Editで列挙されないのであれば望み無しです。)

ダミーフレーム挿入に関しては、そのような感じです。

そういえば、もしかしたらAVIには「フレームデータ省略」というフラグのようなものがあったような気もしてきました。そういうものが本当にあったかどうかはっきりとは覚えていないのですが。もしそういうものがあれば、ダミーフレームを書くよりは省略フラグを立てておくほうが良さそうですね。

この回答への補足

いろいろとやってみました。

実際の録画時間と再生時間は必ずしも同じにはならないようですね。
しかし、再生時間が録画時間の5~3分の1というのは明らかにおかしいですよね。

Video for WindowsのAVIStreamWriteを使って出力しています。
AVIStreamWriteを呼び出している自前の関数で、出力間隔を調節するようにしましたが、フレーム数が明らかに足りないんです。
基準とする間隔は、1000/30(1秒/30)にしています。
調節した間隔は画像取得を行う間隔ではないのがまずかったでしょうか?
AVIStreamWriteを呼び出す自前の関数を無限ループで呼び出すように作ってありますが、呼び出す間隔は50ms(GetTickCountで計算)くらいです。

あと、デバイス列挙については、GraphEditorでも列挙されませんでした。

補足日時:2005/07/25 19:23
    • good
    • 0

デバイスの列挙で見つからないという点については、DirectShowに付属のユーティリティGraphEdit (GraphEdt.exe)を使って、フィルタ一覧の中にそのデバイスに対応するキャプチャフィルタが表示されるかどうか確認してみてください。



もし一覧の中に表示されていれば、そのデバイスは列挙可能です。一覧の中に表示されていないのであれば、残念ながらそのデバイスはDirectShowでは使えません。

もっとも、Video for WindowsのデバイスもDirectShowは列挙するので、DirectShowで列挙されないということはDirectShowでもVideo for Windowsでも使用できないデバイスということになります。そんなビデオキャプチャデバイス本当に存在するんかいな?とちょっと疑問に思います。


フレームのダミー挿入については、何も絵的に前フレームと後フレームの中間になるようなものを計算して作成したりする必要はなく、単に同じフレームを複数回出力すればよろしいかと思います。同じフレームを出力するのは簡単ですので。

どのくらいの間隔が適当かについては、いろいろ考え方があると思います。キャプチャしたフレームを1枚も無駄にしないことが目標であれば、最大フレームレートと同じ(かそれより短い)間隔にすることになりますし、生成するAVIファイルの内容が「毎秒5コマあれば十分だ」と判断されるのであれば200msで良いことになります。

この回答への補足

ありがとうございます。

>もっとも、Video for WindowsのデバイスもDirectShowは列挙するので、DirectShowで列挙されないということはDirectShowでもVideo for Windowsでも使用できないデバイスということになります。そんなビデオキャプチャデバイス本当に存在するんかいな?とちょっと疑問に思います。

カテゴリCLSID_VideoInputDeviceCategoryによるCreateClassEnumeratorではデバイスが列挙されないが、CLSID_VideoInputDeviceCategory以外のカテゴリでなら列挙できるということですよね?

調節する場合、例えば、前回フレーム出力時からの間隔が定義済みフレーム間隔の2倍だったときは、ダミーを1枚挿入、3倍だったときは2枚挿入して、実フレームを書き込めば良いということですよね?

補足日時:2005/07/24 23:47
    • good
    • 0

AVIファイルのヘッダにあるAVIMAINHEADER構造体にdwMicroSecPerFrameというメンバがあり、「フレーム間の間隔をマイクロ秒単位で指定する」とされています。



この値がゼロあるいは実際のフレーム間隔より小さい値ですと、早送りのようになってしまいます。
    • good
    • 0

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