アプリ版:「スタンプのみでお礼する」機能のリリースについて

現在、複数USBカメラを使用してシステムを作成して居ます。
必要があって、カメラのフレームレートを下げようとしています。

関連質問
http://oshiete.goo.ne.jp/qa/7204105.html

フレームレートに関するものを調べるとAvgTimePerFrame、GetOutputFPS、SetOutputFPSがあります。

AvgTimePerFrameについてはプログラム出来ておりますが、GetOutputFPS、SetOutputFPSが出来て居ません。

現在、色々試して居ますが、基本的な事が判って居ないので解決策が見当たらない現状です。

で、AvgTimePerFrame、GetOutputFPS、SetOutputFPSの違いは何でしょうか。
AvgTimePerFrameがカメラのフレームレートを100nS単位で通知してくれる、
GetOutputFPSはカメラのフレームレートを1秒間のフレーム数で通知してくれる、
SetOutputFPSはカメラのフレームレートを1秒間のフレーム数で設定する、は理解して居ます。

私の使用しているカメラはロジクールのC905Mで、このカメラは23種類の解像度を持ち、AvgTimePerFrameを使用して各解像度で登録されているだろう3種類のフレームレート640x480は333333、低解像度は666666、高解像度は20000000が入手出来ています。

一方、GetOutputFPSはどの解像度を選択しても15FPSが帰って来ています。
もちろん、プログラムミスであろう事は判っていますがGetOutputFPS、若しくはSetOutputFPSを使用する際、上記の解像度指定が予め必要なのでしょうか、それとも解像度を指定してあれば、その解像度に対するフレームレートの取得、若しくは設定が出来るのでしょうか。
因みにAvgTimePerFrameの時は解像度を選択して値を入手して居ります。

おわかりに成る方が居られましたら宜しくご回答下さい。

A 回答 (9件)

それは想像以上の現場でした。



やはり、普通だったら
AvgTimePerFrameから
IAMStreamConfig::SetFormat
で出来るであろう、というところというわけで


>現在、ワークの隙間を検査する為にUSBカメラ14台を接続し隙間44箇所の検査をする装置を検討していますが、タクトが50秒、キャプチャーを工夫して25秒まで持って行きましたけど、さすが今回はカメラ指定させてもらいました。


すべて、ロジクールのC905Mに、ということでしょうか?


この場合は

同様にロジクールのC905Mを複数台持っていて、且つそれにもC++にもDirectShowにも十分詳しい人が、一部始終が同じコードで同様の結果になることを確認した後で、コードを細かくチェックし原因を究明する、というのが最も確実な方法と思います。
(現状では私に言えることはこれぐらいです。)


もし全てのコードの提示が不可であれば、まず前提として
・USBカメラ14台の列挙は確実にできているか
・フレームレート以外についても変更はうまくいかないか

このあたりの情報もあるといいと思います。
    • good
    • 0
この回答へのお礼

残念ながら考えて居た事は動作しませんでした。
まぁ、FPSが設定されても、カメラのドライバーがそれを見ているとの確認は出来ないので、今日、FPSの設定は失敗との報告書を書きました。

色々ありがとうございました。

お礼日時:2012/01/05 18:38

なるほど、そういう状況でしたか。



あまりに長いと把握するのも大変なのであれですが
(Builderの独自拡張等を除く)C++のクラスの仕様への造詣という事でいえば、私は結構なレベルだと思うので、もしこれがコード上のバグ、という事であるならば

コードをC++の便利仕様を適宜利用して整形し
スパゲティコードを緩和してバグを発見しやすくする

といったことは、多少は出来るかもしれません。
(下の質問はどちらかというとそういう意図が強いです)


複数台USBでつなぐとうまく機能しないカメラも存在し得る…?
という情報も(真偽のほどは全く分かりませんが)

http://hpcgi1.nifty.com/MADIA/Vcbbs/wwwlng.cgi?p …


そこまでのことはさすがになかった、としても、ドライバがらみの特有の問題である可能性も、0ではないのかもしれません。日本語版MSDNフォーラムにもこのような質問ページがありました。

http://social.msdn.microsoft.com/Forums/ja-JP/vc …
    • good
    • 0
この回答へのお礼

画像が黒と言うのは体験しています。
リトライをプログラムして回避しました。

後、現場で調子が悪いので見に行ったら、自動調光しか選択出来ないカメラを使用していて、ワークが入っていない時は明るいので、絞りが利いてしまい、ワークが入ると暗く成って、暫くすると調光されて明るくなる。
プログラムの方はそんなカメラとは知らないから、明るく成る前に撮影してしまい、画面が暗くてNG判断です。
これもリトライを付けて回避しました。

カメラは何を付けても良いとして、ハードは現場任せ、ソフトのみの提供の為に現場がどんなハードを使っているか分からず大変です。
因みに、その現場が使っていたカメラの名前がTAKO、笑っちゃいました。

現在、ワークの隙間を検査する為にUSBカメラ14台を接続し隙間44箇所の検査をする装置を検討していますが、タクトが50秒、キャプチャーを工夫して25秒まで持って行きましたけど、さすが今回はカメラ指定させてもらいました。

工業用カメラを使うのは予算的に許されません。隙間検査はキーエンスの検査ヘッドは1台150万円。
それを44箇所USBカメラで40万位であげて居るのですから性能は専門機と比べないで欲しい。
でも、現場は当然精度を言って来ますよね。

又、愚痴です。

お礼日時:2011/12/27 00:26

ってことは、変更できそうですねぇ(苦笑)



FRedFPSとかに至る前にも

ICaptureGraphBuilder2
IGraphBuilder
ICreateDevEnum
IEnumMoniker
IMoniker
IBaseFilter

などのポインタを使ったりして

色々なことを下準備としてやってると思うのですが

その辺を見せていただくことは可能でしょうか?
    • good
    • 0
この回答へのお礼

色々ありがとうございました。

本日も色々試行錯誤しておりました。
そして、ついに禁断の(笑)USAの質問サイトを除いて見ると、私の質問と同じ質問がありました。
複数カメラで帯域が足りないのでフレームレートを下げたいと。
そしてその回答はLongSecret様のものと同じでした。
と言う事はAvgTimePerFrameに値を書き込むのが正解。

ではなぜ再度フレームレートを取得した時に333333に戻ってしまうのか。
そこで何処で333333に戻ってしまうか調べて見た所、 pStreamConfig->Release(); の様でした。
今はフレームレート読み込みと書き出し関数でpStreamConfig->の設定と解除を行っていますが、別の所で設定、プログラム終了時に解除をやればひょっとして動作するかも知れません。
もう少し試行錯誤続けてみます。

お礼日時:2011/12/26 21:04

うううん



C++ Builderの__propertyの仕様を把握してないのと

検証プログラム
の各独自変数の型が分からないのですが
それらが私の予想通りであるなら

確かに、アプローチ方法が違うのかもしれません。


Webカメラを借りられたので試してみたのですが

pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);

直後の
scc.MinFrameInterval

scc.MaxFrameInterval
の数値はどうなっているでしょうか?


こちらではどちらも333333だったので変化させられない、という結果でしたが

TinyPineさんの方でももし同じ結果が出るのであれば

もしかすると、IAMStreamConfig::SetFormat で操作できる対象について、これもまた前提が間違っているのかもしれません。

この回答への補足

scc.MinFrameIntervalは333333
scc.MaxFrameIntervalは666666

と成っています。

補足日時:2011/12/24 23:09
    • good
    • 0

>pVideoHeaderが無いとのエラーメッセージが出ましたので2行目を追加してやってみましたが、結果は次の読み込みで333333が返って来てしまいました。



333333が返ってくるというのはSetSizeIndexをやることによって


C++Builder専用の予約語「__property」がついた

__property int prSizeIndex = {read=FSizeIndex, write=SetSizeIndex};

によって、別途メンバ

int FSizeIndex; //おそらくこういうことかな?

が333333になる、という意味でしょうか?


下のSetSizeIndex関数の途中まででは
FSizeIndexというのが出てきていないので

その辺がどんな感じになっているかを含め、今一度SetSizeIndex関数の全貌が知りたいです。

そうではないのであれば、どの時点で何をチェックしたら333333になっているという意味なのかも正確にコードとして教えていただけますか?

この回答への補足

AvgTimePerFrameはフレームレートを100nS単位で返します。
即ち333333は約30FPSと言う事に成り、現在接続されているカメラの解像度が640x480モードに成って居て、そのフレームレートが30FPSですので正しい事になります。
但し先のプログラムでAvgTimePerFrameに対して666666、実際のプログラムでは近い値を取ると書かれて居たので、333333に成っては困るので少し大きい777777を設定しました。
その結果、再度AvgTimePerFrameを読み込んだ時、333333に成ってしまったと言う事です。

先程、会社で使用しているプログラムと同じ様にRedFPSとWitFPSを作りましたので、全てのプログラムを載せます。

//***FPS読み出し**********************************************
int __fastcall TWebCam::FRedFPS( int Index )
{
int iFrmSpd;
//分解能コントロール
IAMStreamConfig *pStreamConfig;
//キャプチャピンに対してストリームコングィグをセット
FCapture->FindInterface(&PIN_CATEGORY_CAPTURE, //キャプチャピン
0,//すべてのメディアタイプ
FVideoCap, IID_IAMStreamConfig, (void **)&pStreamConfig );

AM_MEDIA_TYPE *pmt;
VIDEO_STREAM_CONFIG_CAPS scc;
//フォーマットリストの取得
HRESULT hr;
// フォーマット機能の取得 機能番号はIndexに設定
hr=pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);
if(hr!=S_OK){
ShowMessage("Format change error(1).");
return 0;
}
// フォーマットの設定
hr = pStreamConfig->SetFormat(pmt);
if(hr!=S_OK){
ShowMessage("Format change error(2).");
return 0;
}
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)pmt->pbFormat;
// ビットマップ情報を BITMAPINFO 構造体にコピーする

// これはテスト用、今の所、選択されたカメラ、解像度番号のタイミングが入手出来ている様だ。
// 一方GetOutputFPSはどの解像度でも15が返ってくる。アクセス箇所位置が違う?
iFrmSpd = pVideoHeader->AvgTimePerFrame; // フレームタイミング入手

// ここからGetOutputFPS用のプログラム
/*IAMTimelineObj* pVideoGroupObj;
IAMTimeline* pTimeLine;

CoCreateInstance(CLSID_AMTimeline, NULL, CLSCTX_INPROC_SERVER,
IID_IAMTimeline, (void**)&pTimeLine);
pTimeLine->CreateEmptyNode(&pVideoGroupObj, TIMELINE_MAJOR_TYPE_GROUP);

IAMTimelineGroup* pVideoGroup;
pVideoGroupObj->QueryInterface(IID_IAMTimelineGroup, (void**)&pVideoGroup);
double dTmp;

pVideoGroup->GetOutputFPS(&dTmp); // 読み出しフレーム/秒
*/
return( iFrmSpd) ;
}
//***FPS書き出し**********************************************
void __fastcall TWebCam::FWteFPS( int Index, int iPar )
{
int iFrmSpd;
//分解能コントロール
IAMStreamConfig *pStreamConfig;
//キャプチャピンに対してストリームコングィグをセット
FCapture->FindInterface(&PIN_CATEGORY_CAPTURE, //キャプチャピン
0,//すべてのメディアタイプ
FVideoCap, IID_IAMStreamConfig, (void **)&pStreamConfig );

AM_MEDIA_TYPE *pmt;
VIDEO_STREAM_CONFIG_CAPS scc;
//フォーマットリストの取得
HRESULT hr;
// フォーマット機能の取得 機能番号はIndexに設定
/*hr=pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);
if(hr!=S_OK){
ShowMessage("Format change error(1).");
return;
}
// フォーマットの設定
hr = pStreamConfig->SetFormat(pmt);
if(hr!=S_OK){
ShowMessage("Format change error(2).");
return;
}
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)pmt->pbFormat;
// ビットマップ情報を BITMAPINFO 構造体にコピーする

// これはテスト用、今の所、選択されたカメラ、解像度番号のタイミングが入手出来ている様だ。
// 一方GetOutputFPSはどの解像度でも15が返ってくる。アクセス箇所位置が違う?
((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = iPar; // フレームタイミング入手
// AvgTimePerFrameはここまで */
pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);

VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)pmt->pbFormat;

((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 777777;

pStreamConfig->SetFormat(pmt);

iFrmSpd = pVideoHeader->AvgTimePerFrame;


return;
}

プロパティー
void __fastcall SetSizeIndex( int Index );//選択サイズ
void __fastcall FWteFPS( int iPar, int Index );//選択サイズ
int __fastcall FRedFPS( int iPar );//選択サイズ
__property intprSizeIndex = {read=FSizeIndex, write=SetSizeIndex};
__property intprCamFPS[int iPar] = {read=FRedFPS, write=FWteFPS};

検証プログラム
FCams->prCam[iCam]->prSizeIndex = iRes[iCam]; //解像度設定、Grabbバッファー取得
iFps = FCams->prCam[iCam]->prCamFPS[iRes[iCam]]; //解像度設定、Grabbバッファー取得

FCams->prCam[iCam]->prCamFPS[iRes[iCam]] = iFps * 3;

iFps2 = FCams->prCam[iCam]->prCamFPS[iRes[iCam]];
sWrk.printf( "First %d Second %d", iFps, iFps2 );
ShowMessage( sWrk );

宜しくお願い致します。 文字数オーバーの為原型のSetSizeIndexは載せられませんでした。

補足日時:2011/12/24 21:57
    • good
    • 0

なるほど、分かりました。



これですと

前回質問の3の

ーーーーーーーーーー

hr = pStreamConfig->SetFormat(pmt);

するまえに

((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 数値;

的なことをするとどうなるのでしょうか?

ーーーーーーーーーー

のうち、前半部分を満たしていません。
これにからんでるとこだけ抜粋すると


pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);
pStreamConfig->SetFormat(pmt);

int iFrmSpd = pVideoHeader->AvgTimePerFrame;
((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 666666;
iFrmSpd = pVideoHeader->AvgTimePerFrame;


この順番になってしまっています。
私の提案は


pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);

((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 666666;

pStreamConfig->SetFormat(pmt);

int iFrmSpd = pVideoHeader->AvgTimePerFrame;

この順番、ということです。




どういう事かと言いますと
SetFormatの後でメモリ上でいくら数値をいじくりまわしても
それがデバイス(カメラ)に伝わらないとダメという事です。


Debug::f(int); でintの数値を表示するとしたら

例えば


int 能力 = 100;

void func(){

int a = 能力;

Debug::f( a ); //もちろん、100と表示される。

a = 30;

int b = a;

Debug::f( b ); //もちろん、30と表示されるが、「能力」が書き変わったわけではない。

}

というのとまったく同じことになっているわけです。


デバイスドライバって言うのは基本的に

デバイス(この場合カメラ)
と、PCのメモリやCPUは離れた場所にあるのだから
通信には多かれ少なかれ時間がかかる

なので、ある程度まとまった情報を

特定の関数からのみやりとりすることで
そのオーバーヘッドを避ける


という風に作られてるのが普通です。


そう考えれば、内部的な動作がだいたい予想できるのではないでしょうか?


なお
IAMStreamConfig::GetStreamCapsのMSDNの解説にもありますが


pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);


として得たpmtは、情報を得るために内部的に領域が確保されてるので

使い終わったら

DeleteMediaType(pmt);

として解放してください。

この回答への補足

再度のご指摘ありがとうございます。

pVideoHeaderが無いとのエラーメッセージが出ましたので2行目を追加してやってみましたが、結果は次の読み込みで333333が返って来てしまいました。

pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);

VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)pmt->pbFormat;

((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 666666;

pStreamConfig->SetFormat(pmt);

iFrmSpd = pVideoHeader->AvgTimePerFrame;

補足日時:2011/12/24 19:58
    • good
    • 0

むむ?



>この関数を2回読んで見ました。

「この関数」と、いいますのは
前回質問の
int __fastcall TWebCam::RedFPS( int Index )
のことでしょうか?
(これをIndexを全く同じのを指定して2回、ということでしょうか?)

状況が正確に分からないと判断が難しいので、ここはひとつ

IAMStreamConfig::GetStreamCaps関数を呼び出したとこから

前回質問のコードにおける

// ここからGetOutputFPS用のプログラム
IAMTimelineObj* pVideoGroupObj;
IAMTimeline* pTimeLine;

までの間の、現在のコードを正確に教えてください。

この回答への補足

http://d.hatena.ne.jp/xabre/20070909/1189347523

の記述もあるので出来るのかも知れませんね。よくわかりません。

テストしたプログラムはこれです。
質問に載せたのは会社で使っているプログラムで、ここでは家にあった会社で使ったプログラムの原型を改造したので、関数名は異なります。


//***選択サイズ**********************************************
void __fastcall TWebCam::SetSizeIndex( int Index )
{
//分解能コントロール
IAMStreamConfig *pStreamConfig;
//キャプチャピンに対してストリームコングィグをセット
FCapture->FindInterface(&PIN_CATEGORY_CAPTURE,//キャプチャピン
0,//すべてのメディアタイプ
FVideoCap, IID_IAMStreamConfig, (void **)&pStreamConfig );

AM_MEDIA_TYPE *pmt;
VIDEO_STREAM_CONFIG_CAPS scc;
//フォーマットリストの取得
HRESULT hr;
// フォーマット機能の取得 機能番号はIndexに設定
hr=pStreamConfig->GetStreamCaps(Index,&pmt,(BYTE*)&scc);
if(hr!=S_OK){
ShowMessage("Format change error(1).");
return;
}
//フォーマットの設定
hr = pStreamConfig->SetFormat(pmt);
if(hr!=S_OK){
ShowMessage("Format change error(2).");
return;
}

VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)pmt->pbFormat;
// ビットマップ情報を BITMAPINFO 構造体にコピーする
ZeroMemory( &FBitmapInfo, sizeof(BITMAPINFO) );
CopyMemory( &(FBitmapInfo.bmiHeader), &(pVideoHeader->bmiHeader),
sizeof(BITMAPINFOHEADER));
//画像バッファの更新
if( FImageSize!=(long)FBitmapInfo.bmiHeader.biSizeImage ) {
// FBitmapInfo.bmiHeader.biSizeImageに正しいバッファーサイズが入って来ないカメラがあるので算出
//FImageSize = FBitmapInfo.bmiHeader.biSizeImage;
FImageSize = FBitmapInfo.bmiHeader.biWidth * FBitmapInfo.bmiHeader.biHeight * 3;
if( FImage ) {
// delete[] FImage;
VirtualUnlock( FImage, FImageSize );//メモリの開放
VirtualFree( FImage, 0 , MEM_RELEASE );
FImage = NULL;
}
// FImage = new BYTE[FImageSize];
FImage = (PBYTE)VirtualAlloc( NULL, FImageSize, MEM_COMMIT, PAGE_READWRITE );
if( FImage ) {
if( !VirtualLock( FImage, FImageSize) ) {//メモリのロック
VirtualFree( FImage, 0 , MEM_RELEASE );
FImage = NULL;
throwException("Faild to get image memory from the system.(03)");
}
} else {
throwException("Faild to get image memory from the system.(04)");
}
}

// AvgTimePerFrame の読み出し、書き込み
int iFrmSpd = pVideoHeader->AvgTimePerFrame; // フレームタイミング入手



((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 666666;


iFrmSpd = pVideoHeader->AvgTimePerFrame; // フレームタイミング入手

// AvgTimePerFrameはここまで

// ここからGetOutputFPS用のプログラム

IAMTimelineObj* pVideoGroupObj;
IAMTimeline* pTimeLine;


呼び出し側は

if( bDbg == false )
{ if( iRes[iCam] >= 0 )
{
FCams->prCam[iCam]->prSizeIndex = iRes[iCam]; //解像度設定、Grabbバッファー取得
FCams->prCam[iCam]->prSizeIndex = iRes[iCam]; //解像度設定、Grabbバッファー取得
sSetCam( iCam ); // カメラパラメーターの設定
}
}

プロパティーの設定として

void __fastcall SetSizeIndex( int Index );//選択サイズ
//選択サイズ
__property intprSizeIndex = {read=FSizeIndex, write=SetSizeIndex};

補足日時:2011/12/24 18:48
    • good
    • 0

ご提示いただいたMSDNのページは


Visual Basic オブジェクトである

IBasicVideo2.AvgTimePerFrame

についてのことで、メンバ名は同じですが
VIDEOINFOHEADER 構造体とは事情が異なると考えれます。




ビデオ出力フォーマットの設定
http://msdn.microsoft.com/ja-jp/library/cc353344 …

の下の方に


特定のフレーム レートを要求するには、メディア タイプにある構造体 VIDEOINFOHEADER か VIDEOINFOHEADER2 の AvgTimePerFrame の値を変更する。デバイスは最小値と最大値の間で可能なすべての値はサポートしていないことがあるため、ドライバは使用可能な最も近い値を使う。ドライバが実際に使った値を調べるには、SetFormat を呼び出した後に IAMStreamConfig::GetFormat を呼び出す。


といった記述があるので、変更してSetFormatを呼び出すことは、自然な行動の一つなのではないかな、と思われます。

この回答への補足

今 下記の様にコーディングしてこの関数を2回読んで見ました。

1回目のiFrmSpdには333333が返って来て、2000000を設定した後のiFreSpfには2000000が返って来るのですが、再度この関数を呼び出した最初のiFrmSpdではやはり333333が返って来てしまいました。


int iFrmSpd = pVideoHeader->AvgTimePerFrame; // フレームタイミング入手



((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 2000000;


iFrmSpd = pVideoHeader->AvgTimePerFrame; // フレームタイミング入手

補足日時:2011/12/24 17:59
    • good
    • 0

>GetOutputFPSはカメラのフレームレートを1秒間のフレーム数で通知してくれる、


>SetOutputFPSはカメラのフレームレートを1秒間のフレーム数で設定する

MSDN解説を読む限り、この二つはカメラサイドではなく、タイムラインに対して効果があります。


とりあえず、確認だけ
前回質問のNo.3の内容は試してみたが、変化がない、という事でしょうか?

IAMStreamConfig::GetStreamCapsについて
http://msdn.microsoft.com/ja-jp/library/cc355061 …

IAMStreamConfig::SetFormatについて
http://msdn.microsoft.com/ja-jp/library/cc355073 …

AM_MEDIA_TYPE 構造体について
http://msdn.microsoft.com/ja-jp/library/cc352096 …

この回答への補足

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

前回の回答3
>((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame = 数値;
>的なことをするとどうなるのでしょうか?

ですが、以下のところにこのプロパティーは読み取り専用との記述があり、その為にSetOutputFPSの実行を試みています。
ただ、私の知識からすると、このSetOutputFPS自体、どの様に使うものか理解して居りませんので、機能が少しわかれば解決策も生まれるのでは無いかと思い
新たな質問を立ち上げさせて頂きました。
http://msdn.microsoft.com/ja-jp/library/cc352251 …

補足日時:2011/12/24 16:53
    • good
    • 0

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