• 締切済み

解像度と誤差について

失礼します。 OpenCVという画像処理ライブラリを用いてテンプレートマッチング法を使った物体追跡を行っています。 今、観測画面内でテンプレート画像とマッチングした箇所を矩形で囲んでその部分の座標X,Y(単位[pixel])を随時コマンドプロンプトに表示させています。 このとき、矩形で囲んでいる物体が一定の場所に置いてあっても、コマンドプロンプト上に表示させている座標にプラスマイナス2[pixel]ぐらいの誤差が生じてしまいます。 この誤差というのは[pixel]→[mm]に単位変換した場合どのくらいの誤差になるのでしょうか?? パソコンはWindows XPでモニターサイズは普通の15インチ(72dpi?)だと思います。観測画面は640×480の解像度でキャプチャーしています。 どうでもいいかもしれませんがmain内のテンプレートマッチングに関係した分のプログラムだけ貼っておきます。 よろしくお願いします。 int main( void ) { int device1 = 0; int key=0; double max_interlinkage=0; double min_interlinkage=0; int X1 = 351; int X2 = 351; int Y1 = 349; int Y2 = 349; CvPoint end_point1; CvPoint end_point2; CvPoint max_point; CvPoint min_point; CvPoint corner_point; char windowNameTemplate[] = "Template"; // テンプレート画像を表示するウィンドウの名前 char windowNameDestination[] = "Destination"; // マッチング結果を表示するウィンドウの名前 //videoInputオブジェクト videoInput VI; //利用可能なキャプチャデバイス数を取得 int numDevices = VI.listDevices(); //キャプチャデバイスが見つからなかったら終了 if(numDevices == 0) { cerr << "[Error] Capture device not found!!" << endl; exit(-1); } //デバイス初期化(今回はデバイスID = 0,CAPTURE_WIDTH x CAPTURE_HEIGHTでキャプチャ) VI.setupDevice(device1, CAPTURE_WIDTH, CAPTURE_HEIGHT); IplImage *templateImage = cvLoadImage( "C:/Documents and Settings/ito/デスクトップ/cv_samples/image/temp.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); IplImage *tempGray = cvCreateImage( cvGetSize(templateImage), IPL_DEPTH_8U, 1 ); if ( templateImage == NULL ) { // 画像が見つからなかった場合 printf( "画像が見つかりません\n" ); return -1; } cvCvtColor(templateImage,tempGray,CV_BGR2GRAY); IplImage *frameImage = cvCreateImage( cvSize(CAPTURE_WIDTH, CAPTURE_HEIGHT), IPL_DEPTH_8U, 3 ); // 画像用IplImage IplImage *grayImage = cvCreateImage( cvSize(CAPTURE_WIDTH, CAPTURE_HEIGHT), IPL_DEPTH_8U, 1 ); // 元画像をグレースケール化した画像用IplImage IplImage *dstImage = cvCreateImage( cvSize( frameImage->width - templateImage->width + 1, frameImage->height - templateImage->height + 1 ), IPL_DEPTH_32F, 1 ); // 相違度マップ画像用IplImage memcpy(frameImage->imageData, VI.getPixels(device1, false , true), frameImage->imageSize); cvCvtColor(templateImage,tempGray,CV_BGR2GRAY); //ループ開始 while(1){ //カメラ・デバイスから画像取得 memcpy(frameImage->imageData, VI.getPixels(device1, false , true), frameImage->imageSize); cvCvtColor(frameImage,grayImage,CV_BGR2GRAY); end_point1=cvPoint(X1,Y1); end_point2=cvPoint(X2,Y2); cvRectangle(frameImage , end_point1 , end_point2 , CV_RGB(255,0,0) , LINE_THICKNESS , LINE_TYPE , SHIFT); // テンプレートマッチングを行う cvMatchTemplate( grayImage, tempGray, dstImage, CV_TM_CCOEFF_NORMED ); // テンプレートが元画像のどの部分にあるのかという情報を得る cvMinMaxLoc( dstImage, &min_interlinkage, &max_interlinkage, &min_point, &max_point, NULL ); if(max_interlinkage>0.60){ corner_point=cvPoint(max_point.x+templateImage->width , max_point.y+templateImage->height); printf("point x=%d ",max_point.x+templateImage->width); printf(" y=%d ",max_point.y+templateImage->height); cvRectangle(frameImage , max_point , corner_point , CV_RGB(255,0,0) , LINE_THICKNESS , LINE_TYPE , SHIFT); printf("\n"); }else{ printf("point Lost\n"); }

みんなの回答

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.6

観測領域の640×480とか、カメラの解像度1600×1200とか、そういう数値をいくら並べ立てた所で、絶対に答えはでません。 唯一の方法は「被写体の円マークの大きさを計り、その円マークが何ピクセル分の画像になったか、手でドット数を数える」しかありません。 例えば、手でドット数を数えて「直径19.6mmの円マークの被写体は、253ドットくらいで写ってる」との結果になれば、1ドットは「19.6÷253(mm)」と判ります。2ドットなら「19.6÷253×2(mm)」なので「2ドットは約0.154mm」と判ります。 ぶっちゃけ、貴方が「解像度は…」とか「DPIは…」とか「観測領域は…」とか言った所で、絶対に答えは出ません。 で、画像1枚だけを数えても意味無いから、サンプル画像4~50枚で円が何ドットの大きさで写ってるか全部数え、平均を求めよう。 平均した値が「画像1ドットの大きさの平均」になるので、それを2倍すれば「画像2ドットの大きさの平均」になるから、それが求めたい「ミリ単位での誤差の平均」になる。 インテリや学者の欠点は「頭でだけで考えて行き詰まって悩む」と言う点。頭で考える前に先に手が動いてしまう「インテリでも学者でもない人」は、何も悩まず、まず「手作業」と言う強引な手段(今回の場合は、画像のドット数を数える)に訴えて簡単に問題を解決してしまいます。理論なんか、後から幾らでも辻褄合わせ出来ます。

回答No.5

こんにちは. リンク先のサイトは「画面上の画像を印刷したときにどのくらいのサイズになるか」, を計算する目的であるように思います. pointやpica,級というのは印刷で使われる単位だからです. 例えば級は写植機の送り装置のギアの回転に基づく単位です. 透視投影とは「遠くのものほど小さく映る」モデルです. ですから,奥行きの情報無くして画像領域の物理的なサイズは計算できません. さらにmm単位への変換には,「mm単位の焦点距離」, 「撮像素子の物理サイズ」,「画素単位の焦点距離」のうち二つが必要不可欠です. これは透視投影というカメラの数学モデルの基礎ですが, 再三申し上げているこの内容もご理解いただけないようなので, これを最後にしたいと思います. 少々厳しい物言いになりますが, まともな書籍や文献を当たることなくWeb検索を繰り返している限り, あなたが正解に到達することは無いでしょう.

回答No.4

おはようございます. 重要なのは焦点距離(f=25mmとか書かれているあれです)と撮像素子のサイズです(こちらもmm単位). これがあれば, 「光学中心からf mmだけ離れた像面上の一辺n mm の矩形領域は, 光学中心からZ mm だけ離れた場所において N mmなるサイズだから…」 と計算すれば良いわけです (さすがに透視投影モデルについてはご存じですよね?). なのですが,上記の量が公開されていない場合もあります. 一応,計算で焦点距離を求めることも可能なのですが, この処理はかなり面倒なのでおすすめしません. 興味がある場合はOpenCVのCamera Calibrationで調べてみてください. Zhangの方法と呼ばれるカメラ校正法に行き着くはずです. この方法によれば「fは何画素分か」が分かります. 後はこれに画素の物理的なサイズを乗ずれば良いはずです. 色々勘案すると,「円が円として映る状況」で「右にN mm動かしたときに中心が m 画素ずれた, だからこの奥行きにおいて 1 画素は N/m mm くらいだろう」とやるのが一番簡単です. ところで,「フレームレート」というのは1秒当たりに何枚画像を撮影できるか, ということではないのですか? 「アナログなテレビのフレームレートは29.97fps」と言った場合, 100秒で2997枚の画像が出てくるという意味なのですが…

berserk_00
質問者

お礼

回答ありがとうございます。 OpenCVのCamera Calibrationも少し調べてみようと思います。 「フレームレート」はたしかに1秒当たりに何枚画像を撮影できるかでした。 さらなる勘違いをしていたようで、フレームレートではなく観測画面が「640×480」でした。 解像度などについていろいろ調べてたところ、こんがらがってきてしまったのですが観測画面サイズが「640×480」の場合、その解像度は「640×480dpi」でいいのでしょうか? 余談かもしれませんがpixelをいろいろな単位に変換してくれるサイトをみつけたのですが、このサイトは今回の問題を解決するのに使えるでしょうか?? ppiが出てきて正直混乱してます・・・・ http://www.gem.hi-ho.ne.jp/fortunefield/javascript/pixel.html

回答No.3

こんにちは. 結論から言うと「場合によって異なるので質問文からは絶対に計算できない」です. これは以下のような理由によります. (1)カメラの物理的な情報が皆無 (2)撮影対象の奥行きについて概算すらしていない (3)諸々の不確かさ 順番に説明すると, (1)デジタルカメラを使っているとすれば, カメラの焦点距離とCCD素子のサイズから1画素の物理的な大きさが計算できます. が,この情報が一切書かれていません. (2)画素の物理的なサイズが分かっていても撮影対象の位置によって「1画素」に投影される体積が異なります. 例えば,1mの距離で画像面に正対した20mm平方の平板と2mの距離の40m平方の平板は画像上で同じ大きさ(画素数)に見えます. 対象物体に奥行きがある場合は遠方短縮によってもっと面倒なことになります. (3)「キャプチャ」とありますのでNTSC信号などで入力をしていると思われますが, この場合,A/D変換を経由する都合上,画素のサイズはフレームによって異なります. 入力されたアナログ信号をサンプリングするとしても, その間隔はどうあっても「全く同じ」にならないからです. まとめると,カメラの物理的な情報を調べるのでなければ, 撮影対象を既知の量だけ動かしたときに像面上でどの程度の変位が発生するかを「手で」見積もってください. テンプレートマッチングをしないのはこの処理の評価関数が物理的な計量と無関係だからです. 一般的には評価関数として「画像間の輝度差」を使いますが, これは「対象物体が全く動いてない」状況でも「片方の画像が明るくなる」だけで「誤差」が生じることからも確認できると思います.

berserk_00
質問者

お礼

回答ありがとうございます。 安易に質問してしまいすいません。 情報が足りませんでした。 ☆今使用しているUSBカメラの仕様を確認してみたところ、 撮影素子・画素数:CMOS・200万画素・オートフォーカス 解像度:最大1600×1200 最短接写距離:10cm ☆現在の観測環境 現在は対象物体とカメラ間の距離は15cmほどで観測しています。 それで自分勘違いしていまして、フレームレート=解像度だと思ってました。 なので確認してみたところ、解像度「1600×1200」、フレームレート「640×480」、対象物体とカメラ間距離15cmの環境において直径2cmほどの円を矩形で囲み追跡しています。 調べてみたところ、このくらいだったのですが、他にpixel→mmに単位変換する際に必要な情報はありますか?

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

>この誤差というのは[pixel]→[mm]に単位変換した場合どのくらいの誤差になるのでしょうか?? 「2Pixelは何mmか?」という事でしょうか? >観測画面は640×480の解像度 重要なのは「観測している領域の大きさ」です。 640mm×480mmの領域を640×480の解像度でキャプチャしているなら、1ドットは1mm×1mmです。 320mm×240mmの領域を640×480の解像度でキャプチャしているなら、1ドットは0.5mm×0.5mmです。 64mm×48mmの領域を640×480の解像度でキャプチャしているなら、1ドットは0.1mm×0.1mmです。 質問文には「何mm×何mmの領域を撮影しているか」が書かれていませんので「2Pixelは何mmか?」は判りません。

berserk_00
質問者

お礼

回答ありがとうございます。 >「2Pixelは何mmか?」という事でしょうか? そうですね。2[Pixel]の誤差が[mm]に単位変換すると何mmなのかということです。 >重要なのは「観測している領域の大きさ」です。 すいません、どうも自分勘違いしていたみたいで。。 画像サイズ=解像度だと思っていました。 どうやら違うみたいですね。 使用しているUSBカメラがCMOS200万画素なので、解像度は[1600×1200]に相当するようです。 それで「観測している領域の大きさ」が640×480でした。 まだ[mm]に単位変換するのに情報は足りないでしょうか??

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

単純な度量変換ですよ dpiは ドット パー インチ すなわち 1インチあたりのドット数です 1インチをmmで表す場合 25.4mmとするのが一般的でしょう Pixel / DPI X 25.4 といった式になります 2 / 72 * 25.4 = 0.70555 ぐらいでしょう …

berserk_00
質問者

お礼

ネットで調べればすぐ解決できるような質問でしたね。 回答してくださりありがとうございました!

関連するQ&A

  • OpenCVでのテンプレートマッチングについて

    質問させてください。 現在画像処理ライブラリのOpenCVを使ってテンプレートマッチングを用いた物体追跡しようと考えています。 今回作ってみたのですがどうしても、 「Bad argument(Array should be CvMat or IplImage)in function cvGetSize」 というエラーが出てしまいます。 おそらく画像の読み込みの部分だとは思うのですが・・・・ よろしくお願いします。 ソースプログラムは次のようになってます。 int main( void ) { int device1 = 0; int key=0; double max_interlinkage=0; double min_interlinkage=0; CvPoint max_point; CvPoint min_point; CvPoint corner_point; char windowNameTemplate[] = "Template"; // テンプレート画像を表示するウィンドウの名前 char windowNameDestination[] = "Destination"; // マッチング結果を表示するウィンドウの名前 //videoInputオブジェクト videoInput VI; //利用可能なキャプチャデバイス数を取得 int numDevices = VI.listDevices(); //キャプチャデバイスが見つからなかったら終了 if(numDevices == 0) { cerr << "[Error] Capture device not found!!" << endl; exit(-1); } //デバイス初期化(今回はデバイスID = 0,CAPTURE_WIDTH x CAPTURE_HEIGHTでキャプチャ) VI.setupDevice(device1, CAPTURE_WIDTH, CAPTURE_HEIGHT); IplImage *templateImage = cvLoadImage( "C:/Documents and Settings/ito/My Document/My Pictures/temp.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); IplImage *tempGray = cvCreateImage( cvGetSize(templateImage), IPL_DEPTH_8U, 1 ); if ( templateImage == NULL ) { // 画像が見つからなかった場合 printf( "画像が見つかりません\n" ); return -1; } cvCvtColor(templateImage,tempGray,CV_BGR2GRAY); IplImage *frameImage = cvCreateImage( cvSize(CAPTURE_WIDTH, CAPTURE_HEIGHT), IPL_DEPTH_8U, 3 ); // 画像用IplImage IplImage *grayImage = cvCreateImage( cvSize(CAPTURE_WIDTH, CAPTURE_HEIGHT), IPL_DEPTH_8U, 1 ); // 元画像をグレースケール化した画像用IplImage IplImage *dstImage = cvCreateImage( cvSize( frameImage->width - templateImage->width + 1, frameImage->height - templateImage->height + 1 ), IPL_DEPTH_32F, 1 ); // 相違度マップ画像用IplImage memcpy(frameImage->imageData, VI.getPixels(device1, false , true), frameImage->imageSize); cvCvtColor(templateImage,tempGray,CV_BGR2GRAY); //ループ開始 while(1){ //カメラ・デバイスから画像取得 memcpy(frameImage->imageData, VI.getPixels(device1, false , true), frameImage->imageSize); cvCvtColor(frameImage,grayImage,CV_BGR2GRAY); // テンプレートマッチングを行う cvMatchTemplate( grayImage, tempGray, dstImage, CV_TM_CCOEFF_NORMED ); // テンプレートが元画像のどの部分にあるのかという情報を得る cvMinMaxLoc( dstImage, &min_interlinkage, &max_interlinkage, &min_point, &max_point, NULL ); if(max_interlinkage>0.75){ corner_point=cvPoint(max_point.x+templateImage->width , max_point.y+templateImage->height); printf("point x=%d ",max_point.x+templateImage->width); printf("point y=%d ",max_point.y+templateImage->height); cvRectangle(frameImage , max_point , corner_point , CV_RGB(255,0,0) , LINE_THICKNESS , LINE_TYPE , SHIFT); printf("\n"); }else{ printf("point Lost\n"); } // ウィンドウを生成する cvNamedWindow( windowNameTemplate, CV_WINDOW_AUTOSIZE ); cvNamedWindow( windowNameDestination, CV_WINDOW_AUTOSIZE ); // 画像を表示する cvShowImage( windowNameTemplate, templateImage ); cvShowImage( windowNameDestination , frameImage ); //キー入力 key = cvWaitKey(1); if(key=='q'){ break; }else if(key=='c'){ cvSaveImage("image/frame.bmp",frameImage); } }

  • openCVの動画書き込みのプログラムを作っているのですが・・・

    openCVの動画書き込みのプログラムを作っているのですが・・・ openCVで、読み込んだ動画(元動画)を背景差分法で2値化処理して出来た動画を保存する、というプログラムを作っています。 しかし、保存された動画を見ると、上手く書き込まれていません。というのも、元動画は15秒あるのですが、保存された動画を見ると、わずか2秒ほどで再生が終わってしまいます。 以下がプログラムのソースです。 #include <stdio.h> #include <cv.h> #include <cxcore.h> #include <highgui.h> #define THRESHOLD_MAX_VALUE 255 #define THRESHOLD 45 #define WIDTH 960 #define HEIGHT 540 int main( int argc, char **argv ){ int key; CvCapture *capture = NULL; IplImage *frameImage; IplImage *backgroundImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *grayImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *differenceImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *binaryImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); double fps = 30.0; CvVideoWriter* VideoWriter = cvCreateVideoWriter("binary.avi", CV_FOURCC('F','L','V','1'), fps, cvSize(WIDTH, HEIGHT), 0 ); if ( ( capture = cvCreateFileCapture( "00011.avi" ) ) == NULL ) { printf( "File Not Found\n" ); return -1; } frameImage = cvLoadImage("haikei.bmp"); if(frameImage == NULL){ printf("Can't Get\n"); return -1; } cvCvtColor( frameImage, backgroundImage, CV_BGR2GRAY ); while ( 1 ) { frameImage = cvQueryFrame( capture ); if ( frameImage == NULL ){ break; } cvCvtColor( frameImage, grayImage, CV_BGR2GRAY ); cvAbsDiff( grayImage, backgroundImage, differenceImage ); cvThreshold( differenceImage, binaryImage, THRESHOLD, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY ); cvWriteFrame(VideoWriter, binaryImage); key = cvWaitKey( 10 ); if ( key == 'q' ) { break; } } cvReleaseCapture( &capture ); cvReleaseVideoWriter( &VideoWriter ); cvReleaseImage( &backgroundImage ); cvReleaseImage( &grayImage ); cvReleaseImage( &differenceImage ); cvReleaseImage( &binaryImage ); return 0; } 抽出している際に、プロンプト画面に Compiler did not align stack variables.~ と出てきます。 また、非圧縮などでやると再生が出来ません。 PC環境はWindowsXPです。 助けてください!!

  • コマンドプロンプトからファイルへの出力

    失礼します。 いまテンプレートマッチングを用いた物体追跡を行っています。 画面内に映っている物体のなかでテンプレート画像とマッチした部分を四角で囲み追跡します、さらにその部分のピクセル座標を随時コマンドプロンプトに表示させています。 そこで質問なのですが、このコマンドプロンプトに表示させている座標をtxtファイルに出力させたいのですが可能でしょうか?? ためしに自分でやってみたのですがうまくいきませんでした。。 よろしければアドバイスお願いします。 以下に関係ある部分のソースコードを載せます。 ofstream fout("matchdata.txt"); if(!fout){ cout<<"ファイルをオープンできませんでした。\n"; return 1; }else{ cout<<"ファイルをオープンしました。\n"; } //ループ開始 while(1){ //カメラ・デバイスから画像取得 memcpy(frameImage->imageData, VI.getPixels(device1, false , true), frameImage->imageSize); cvCvtColor(frameImage,grayImage,CV_BGR2GRAY); // テンプレートマッチングを行う cvMatchTemplate( grayImage, tempGray, dstImage, CV_TM_CCOEFF_NORMED ); // テンプレートが元画像のどの部分にあるのかという情報を得る cvMinMaxLoc( dstImage, &min_interlinkage, &max_interlinkage, &min_point, &max_point, NULL ); if(max_interlinkage>0.60){ corner_point=cvPoint(max_point.x+templateImage->width , max_point.y+templateImage->height); //コマンドプロンプトへの表示 printf("point x=%d ",max_point.x+templateImage->width); printf(" y=%d ",max_point.y+templateImage->height); cvRectangle(frameImage , max_point , corner_point , CV_RGB(255,0,0) , LINE_THICKNESS , LINE_TYPE , SHIFT); printf("\n"); } fout<<"point x= "<<max_point.x+templateImage->width<<" y= "<<max_point.y+templateImage->height; fout.close(); // ウィンドウを生成する cvNamedWindow( windowNameTemplate, CV_WINDOW_AUTOSIZE ); cvNamedWindow( windowNameDestination, CV_WINDOW_AUTOSIZE ); // 画像を表示する cvShowImage( windowNameTemplate, templateImage ); cvShowImage( windowNameDestination , frameImage ); //キー入力 key = cvWaitKey(1); if(key=='q'){ break; }else if(key=='c'){ cvSaveImage("image/frame.bmp",frameImage); } }

  • opencvを用いた二値画像のアクセスと座標の取得

    いつもお世話になっています。 opencvを用いたプログラムを作成しています。 真ん中に大きな塗りつぶされた●が1つあるカラー画像を二値画像に変換して、●の部分のすべての座標をとりたいと考えています。(●は大きいので1ピクセルではありません。●を構成しているピクセルの座標すべてをとるといった感じです。) 今、途中まで作成したのですが間違っているところがあると考えられるので、エラーは出ないのですがプログラムが正常に動きません。このプログラム内での間違いであるとは考えられるので、間違っている部分を教えてもらえないでしょうか? よろしくお願いします。 //元のカラー画像 IplImage* image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); IplImage* gray_image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); //二値画像 IplImage* niti_image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); //座標を入れるための配列 int test_width[500]; int test_height[500]; //カラー画像ここでimage画像に大きな●を書きました。これ以降は●がimageに存在するものとして考えてくださいお願いします cvDrawContours( image, hand_contour[0], CV_RGB (0, 0, 0), CV_RGB (0, 0, 0), -1, CV_FILLED, 8 ,cvPoint(0,0)); //グレースケールの作成 cvCvtColor(image,gray_image,CV_BGR2GRAY); // 画像の二値化【判別分析法(大津の二値化)】 cvThreshold (gray_image, niti_image, 90, 255, CV_THRESH_BINARY); int k = 0;      // 左上から順番に画像を見ていく for( int y = 0; y < niti_image->height; y++){ for(int x = 0; x < niti_image->width; x++){ //もし黒色の値が入っていたら配列に座標を代入する if(niti_image->imageData[y * niti_image->widthStep + x * niti_image->nChannels] == 0){ test_width[k] = x; test_height[k] = y;   k++;             }//if } }

  • セグメンテーション違反なってしまいます。

    LinuxでopenCVを使っているのですが、どうしてもセグメンテーション違反が出てしまいます。 画像の輪郭座標の表示をさせたいのですが、どうしたらセグメンテーション違反がとれるのでしょうか? ちなみにプログラムは、 #include<cv.h> #include<stdio.h> #include<cxcore.h> #include<highgui.h> #include<stdio.h> void GetContourFeature(CvSeq *Contour); #define THRESHOLD 10 #define THRESHOLD_MAX_VALUE 50 #define MIN_CONTOUR_COUNT 100 #define CONTOUR_MAX_LEVEL 1 #define LINE_THICKNESS 2 #define LINE_TYPE 8 //座標格納用変数 CvPoint *point; CvPoint pt[200000]; //制御点の座標 int main(int argc, char** argv) { char windowNameSource[]="Source"; char windowNameContour[]="Contour"; IplImage *sourceImage=cvLoadImage(arg[0],CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); if(sourceImage==NULL) { printf("画像が見つかりません\n"); return -1; } IplImage *grayImage=cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U,1); IplImage *binaryImage=cvCreateImage(cvGetSize(sourceImage),IPL_DEPTH_8U,1); IplImage *contourImage=cvCreateImage(cvGetSize(sourceImage),IPL_DEPTH_8U,3); cvCvtColor(sourceImage,grayImage,CV_BGR2GRAY); cvThreshold(grayImage,binaryImage,THRESHOLD,THRESHOLD_MAX_VALUE, CV_THRESH_BINARY); contourImage=cvCloneImage(sourceImage); CvMemStorage *storage = cvCreateMemStorage(0); CvSeq *contours=NULL; CvSize size = cvGetSize(sourceImage); //領域検出用の画像 IplImage* img_tmp = cvCreateImage(size,8,1); int contour_num = cvFindContours(binaryImage,storage, &contours,sizeof(CvContour),CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(0,0)); CvPoint ptMaxDist = cvPoint(-1,-1); double maxValue = 0.0; if(contour_num){ //距離変換画像 IplImage* img_dist = cvCreateImage(size,IPL_DEPTH_32F,1); IplImage* img_dist_norm = cvCreateImage(size,IPL_DEPTH_8U,1); //距離変換 cvDistTransform(binaryImage,img_dist,CV_DIST_L2,3,NULL,NULL); //0-255に正規化 cvNormalize(img_dist,img_dist_norm,0.0,255.0,CV_MINMAX,NULL); //最大距離の値と座標を取得する cvMinMaxLoc(img_dist,0,&maxValue,0,&ptMaxDist,0); cvReleaseImage(&img_dist); cvReleaseImage(&img_dist_norm); } //最大距離の点を持つ輪郭線を探す CvSeq* contour_max = NULL; if((ptMaxDist.x >= 0) && (ptMaxDist.x < size.width) && (ptMaxDist.y >= 0) && (ptMaxDist.y < size.height) && (maxValue > 0.0)) { cvZero(img_tmp); CvSeq* c = contours; for(contours=0;c != NULL;c = c -> h_next){ if(c -> total < MIN_CONTOUR_COUNT) continue; //この輪郭線を塗りつぶす cvDrawContours(img_tmp,c,cvScalarAll(255),cvScalarAll(255),CONTOUR_MAX_LEVEL,LINE_THICKNESS,LINE_TYPE,cvPoint(0,0)); //この領域に最大距離の点があるかどうか if(255.0 == cvGetReal2D( img_tmp, ptMaxDist.y, ptMaxDist.x)) { contour_max = c; break; } } cvReleaseImage(&img_tmp); } //この輪郭線を塗りつぶす cvDrawContours(contourImage,contour_max,CV_RGB(255,0,0),CV_RGB(255,0,0),CONTOUR_MAX_LEVEL,LINE_THICKNESS,LINE_TYPE,cvPoint(0,0)); int i; for (i=0;i < contour_max->total; i++){ point = CV_GET_SEQ_ELEM(CvPoint, contour_max, i); pt[i].x = point->x; pt[i].y = point->y; printf("(%d,%d)\n",pt[i].x,pt[i].y); } cvNamedWindow(windowNameSource, CV_WINDOW_AUTOSIZE); cvNamedWindow(windowNameContour, CV_WINDOW_AUTOSIZE); cvShowImage(windowNameSource,sourceImage); cvShowImage(windowNameContour,sourceImage); cvWaitKey(0); cvSaveImage("counter",contourImage); cvReleaseImage(&sourceImage); cvReleaseImage(&grayImage); cvReleaseImage(&contourImage); cvDestroyWindow(windowNameSource); cvDestroyWindow(windowNameContour); return 0; } です。よろしくお願いします。

  • カメラを用いて動画から画像を取り込みトリミングしようとするプログラムを

    カメラを用いて動画から画像を取り込みトリミングしようとするプログラムを作っています. 最下部のプログラムを貼り付けているところまででデバックしつつ実行すると "OpenCVwithDShow.exe の 0x00462614 でハンドルされていない例外が発生しました: 0xC0000094: Integer division by zero" とエラー文がでてきます. 色々考えたのですが、原因が分からないのでどなたかご教授お願いします. よろしくお願いします. //トリミング CvRect cvClipRect(IplImage *frame, CvRect r) { r.x = 240; r.y = 0; r.width = 1080; r.height = 1680; if (r.x < 0) {r.width += r.x; r.x = 0;} if (r.y < 0) {r.height += r.y; r.y = 0;} if (r.x >= frame->width ) {r.width -= r.x - frame->width ; r.x = frame->width - 1;} if (r.y >= frame->height) {r.height -= r.y - frame->height; r.y = frame->height - 1;} if (r.width > frame->width - r.x) {r.width = frame->width - r.x;} if (r.height > frame->height - r.y) {r.height = frame->height - r.y;} return r; } IplImage *cvCreateSubRectImage(IplImage *frame, CvRect r) { IplImage tmp; CvMat submat; cvGetSubRect(frame, &submat, cvClipRect(frame, r)); cvGetImage(&submat, &tmp); return cvCloneImage(&tmp); } //トリミング終了 int main (int argc, char **argv){ CvCapture *capture = 0; IplImage *frame = NULL; IplImage *frame1 = NULL; IplImage *reduce = NULL; int c; int x,y; int max,min; int h,s; uchar p[3]; LabelingSS labeling; short *src_buf; float centerX,centerY; HANDLE hCom; //トリミング関数 // (1)コマンド引数によって指定された番号のカメラに対するキャプチャ構造体を作成する if (argc == 1 || (argc == 2 && strlen (argv[1]) == 1 && isdigit (argv[1][0]))) capture = cvCreateCameraCapture (argc == 2 ? argv[1][0] - '0' : 0); /* この設定は,利用するカメラに依存する */ // (2)キャプチャサイズを設定する. cvNamedWindow ("Capture", CV_WINDOW_AUTOSIZE); frame1 = cvQueryFrame (capture); src_buf = new short[ frame1->width * frame1->height ]; // (3)カメラから画像をキャプチャする while (1) { frame1 = cvQueryFrame (capture); frame = cvCloneImage(frame1); //トリミング呼び出し CvRect cvClipRect(IplImage *frame, CvRect r); IplImage *cvCreateSubRectImage(IplImage *frame, CvRect r);

  • OpenCVによる時間差表示

    書き込みさせていただきます。 今OpenCVをインストールしてVC++にてプログラミングをしています。 カメラ画像を取得してそこに点を打とうとしています。 //中心 cvCircle(frameImage,cvPoint(320,250),1,CV_RGB(0,255,0),5,8,0); //右隅 cvCircle(frameImage,cvPoint(635,250),1,CV_RGB(0,255,0),5,8,0); //左隅 cvCircle(frameImage,cvPoint(5,250),1,CV_RGB(0,255,0),5,8,0); //上 cvCircle(frameImage,cvPoint(320,470),1,CV_RGB(0,255,0),5,8,0); //下 cvCircle(frameImage,cvPoint(320,5),1,CV_RGB(0,255,0),5,8,0); のようにして無理やり点を作って表示させることができました。 この点を 中心→0秒から5秒まで表示 右隅→5秒から10秒まで表示 左隅→10秒から15秒まで表示 のように時間をずらして表示するようなプログラムを作りたいのですが、やり方が調べてもよくわかりません。 教えていただければ幸いです。 よろしくお願いいたします。

  • OpenCv 透明度について

    OpenCv 透明度について 透明度を表すRGBAのA(アルファチャネル)をいじって画像の透明にしたいのですが、いじってみてもなにも変化がありません。 なにが悪いのかわかりません ↓こんな感じでやってます。 // 画像を読み込む src_img = cvLoadImage(src_imgfile,CV_LOAD_IMAGE_COLOR); //RGBA変換 dst_img = cvCreateImage(cvGetSize(bg_img),IPL_DEPTH_8U,4); cvCvtColor(bg_img,dst_img,CV_RGB2RGBA); //透明度をいじる for ( int y = 0 ; y < dst_img->height ; y++ ) { for ( int x = 0 ; x < dst_img->width ; x++ ) { dst_img->imageData[dst_img->widthStep * y + x * 4 + 3] = -255; } }

  • ファイルへのデータ書き出しが出来なくて困っています。

    openCVを利用し、用意した画像1、画像2間のオプティカルフローを計算し、画像3に描画するというプログラムを組みました。 その過程での、オプティカルフローのx成分「vel_x」、y成分「vel_y」の値をテキストファイルに書き出したいのですが、それぞれ「003B3340」「003B33E0」と記録されるだけで(多分アドレス?)うまくいきません。 どなたか詳しい方、ご教授いただけると幸いです。 環境はWindows XP、Visual C++ .NET2003です。 以下にコードを示します。 #include <cv.h> #include <highgui.h> #include <stdio.h> #include <fstream> const char *imgA_file = "01.bmp"; const char *imgB_file = "02.bmp"; using namespace std; int main(int argc, char** argv){ IplImage *imgA_src = cvLoadImage( imgA_file, -1); //画像読み込み IplImage *imgB_src = cvLoadImage( imgB_file, -1); IplImage *imgA = cvCreateImage(cvGetSize(imgA_src), IPL_DEPTH_8U, 1); cvCvtColor(imgA_src, imgA, CV_BGR2GRAY); IplImage *imgB = cvCreateImage(cvGetSize(imgA_src), IPL_DEPTH_8U, 1); cvCvtColor(imgB_src, imgB, CV_BGR2GRAY); IplImage *vel_x = cvCreateImage(cvGetSize(imgA_src), IPL_DEPTH_32F, 1); //x,y方向の速度を記録するバッファを確保する IplImage *vel_y = cvCreateImage(cvGetSize(imgA_src), IPL_DEPTH_32F, 1); IplImage *imgC = cvCloneImage(imgA); //結果画像用に入力画像をコピーする cvCalcOpticalFlowLK( imgA, imgB, cvSize( 11, 11), vel_x, vel_y); //オプティカルフローを求める,第3引数:ウインドウサイズ ofstream ofx("vel_x.txt"); //vel_x, vel_y のデータをテキストへ書き込み string buf; ofx << vel_x << endl; ofstream ofy("vel_y.txt"); buf; ofy << vel_y << endl; /* FILE *fp1, *fp2; //vel_x, vel_y のデータをテキストへ書き込み fp1 = fopen("vel_x.txt", "w"); fp2 = fopen("vel_y.txt", "w"); fprintf(fp1, "%d", vel_x); fprintf(fp2, "%d", vel_y); fclose(fp1); fclose(fp2); const CvArr *m, *n; // FILE *fp1, *fp2; fp1 = fopen("vel_x.txt", "r"); fp2 = fopen("vel_y.txt", "r"); fscanf(fp1, "%d", &m); fscanf(fp2, "%d", &n); fclose(fp1); fclose(fp2); */ for ( int i=0;i<imgA->height;i+=10 ){ //結果画像の作成 for ( int j=0;j<imgA->width;j+=10 ){ int dx = (int)cvGetReal2D( vel_x, i, j); int dy = (int)cvGetReal2D( vel_y, i, j); cvLine( imgC, cvPoint( j, i), cvPoint( j+dx, i+dy), CV_RGB( 255, 255, 255), 1, 8, 0); cvRectangle( imgC, cvPoint( j+dx-1, i+dy-1), cvPoint( j+dx+1, i+dy+1), CV_RGB( 255, 255, 255), 1, 8, 0); } } cvSaveImage( "03.bmp", imgC); //画像保存 cvReleaseImage( &imgA); cvReleaseImage( &imgB); cvReleaseImage( &vel_x); cvReleaseImage( &vel_y); return 0; }

  • OpenCV2.4.6で色抽出を行いたい。

    Webカメラから取得した映像を用いて色抽出を行いたいです。 システム開発はVisual Studio 2012で言語はC++です。 OpenCV2.4.6を利用しているのですが、サンプルプログラムが古いバージョンで、OpenCV2.4.6では動かないので以下のプログラムを改良したいです。 参考にしたサイトはこちらです。 http://d.hatena.ne.jp/wah-wah-hawah/20090325/1237996168 以下プログラム #include <cv.h> #include <highgui.h> void GetMaskHSV(IplImage* src, IplImage* mask,int erosions, int dilations) { int x = 0, y = 0; uchar H, S, V; uchar minH, minS, minV, maxH, maxS, maxV; CvPixelPosition8u pos_src, pos_dst; uchar* p_src; uchar* p_dst; IplImage* tmp; tmp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3); //HSVに変換 cvCvtColor(src, tmp, CV_RGB2HSV); CV_INIT_PIXEL_POS(pos_src, (unsigned char*) tmp->imageData, tmp->widthStep,cvGetSize(tmp), x, y, tmp->origin); CV_INIT_PIXEL_POS(pos_dst, (unsigned char*) mask->imageData, mask->widthStep, cvGetSize(mask), x, y, mask->origin); minH = 100; maxH = 115; minS = 80; maxS = 255; minV = 120; maxV = 255; for(y = 0; y < tmp->height; y++) { for(x = 0; x < tmp->width; x++) { p_src = CV_MOVE_TO(pos_src, x, y, 3); p_dst = CV_MOVE_TO(pos_dst, x, y, 3); H = p_src[0]; //0から180 S = p_src[1]; V = p_src[2]; if( minH <= H && H <= maxH && minS <= S && S <= maxS && minV <= V && V <= maxV ) { p_dst[0] = 255; p_dst[1] = 255; p_dst[2] = 255; } else { p_dst[0] = 0; p_dst[1] = 0; p_dst[2] = 0; } } } if(erosions > 0) cvErode(mask, mask, 0, erosions); if(dilations > 0) cvDilate(mask, mask, 0, dilations); cvReleaseImage(&tmp); } int main(int argc, char **argv) { int c; CvCapture* capture = 0; IplImage* frame = 0; IplImage* mask = 0; IplImage* dst = 0; if(argc == 1 || (argc == 2 && strlen (argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCreateCameraCapture(argc == 2 ? argv[1][0] - '0' : 0); frame = cvQueryFrame(capture); mask = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3); dst = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3); cvNamedWindow("src", CV_WINDOW_AUTOSIZE); cvNamedWindow("dst", CV_WINDOW_AUTOSIZE); while(1) { frame = cvQueryFrame(capture); GetMaskHSV(frame, mask, 1, 1); cvAnd(frame, mask, dst); cvShowImage("src", frame); cvShowImage("dst", dst); c = cvWaitKey(10); if(c == 'q') break; } cvDestroyWindow("src"); cvDestroyWindow("dst"); cvReleaseImage(&frame); cvReleaseImage(&dst); cvReleaseImage(&mask); cvReleaseCapture(&capture); return(0); }

専門家に質問してみよう