opencvのシーケンスとは?座標の取得方法も知りたい!

このQ&Aのポイント
  • opencvのシーケンスとは、メモリストレージオブジェクトと一緒に使用されるデータ構造です。
  • シーケンスは、画像処理の中でよく使われ、特に輪郭の情報を格納するのに使用されます。
  • CvFindCountorという関数では、引数として渡されたシーケンスに輪郭の情報が保存されています。座標を取得するには、シーケンスの要素を参照することで可能です。
回答を見る
  • ベストアンサー

opencvのシーケンスについて。

opencvのシーケンスについて。 opencvのシーケンスとは。 opencvを使っていると、よくシーケンスという言葉に遭遇します。本やネットで調べましたが、どんなものなのかがよく分かりません。 メモリストレージ・オブジェクト等と一緒に出てくるのですが、これらもなかなか理解しがたいです… 例えばCvFindCountorという画像内のn個の辺を持つ輪郭を調べるという関数がありますが、これに関する情報が引数として渡したシーケンスに保存されているようだ。というのは何となく感じとったのですが、この中の座標等を引き出すにはどうしたらいいのでしょうか。 どなたか分かりやすくご教授頂けないでしょうか。 また、分かりやすいサイトや本もご存知であれば教えて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

CV_GET_SEQ_ELEMで取得する輪郭を構成する頂点座標はcvFindContours関数の6番目の引数methodの設定で取得できる座標が異なります。 method = CV_CHAIN_APPROX_NONEとすると輪郭の座標全てを取得し、 method = CV_CHAIN_APPROX_SIMPLEとすると、輪郭を縦、横、斜め(45°)の直線で構成される折れ線で表した時の角の座標を取得します。 method = CV_CHAIN_APPROX_TC89_L1 もしくは CV_CHAIN_APPROX_TC89_KCOS とすると斜め45°以外の直線も含む、直線で輪郭を近似したときの折れ線の角の座標を取得出来るのですが、直線近似のアルゴリズムは私はあまり良く知りません...

michiko_20
質問者

お礼

ありがとうございます! cvFindCountorsにそんな便利な引数があるとは知りませんでした!! 早速試してみます。 ずっと引っ掛かっていた事がものすごいスッキリとしました!! 本当にありがとうございました!!!

その他の回答 (1)

回答No.1

シーケンスやメモリストレージについては、正直、あまり理解はしていないのですが、cvFindContoursなら...という程度ですが。 シーケンスというのはC言語でいうところの『リスト構造』のようなものだと思います。 例えば、cvFindContoursのような輪郭を抽出する関数では、処理する前からは輪郭の個数は分からないので、輪郭の情報を格納するメモリは予め確保しておく事ができません。 そういう時にC言語ではリストを使います。 リストについては別途調べて頂くと分かると思いますが、例えば、最初に見つかった輪郭の情報を『A』、次に見つかった輪郭を『B』、次が『C』・・・最後に見つかった輪郭が『F』とすると、  A⇔B⇔C⇔D⇔E⇔F というように、それぞれの輪郭の情報に前後関係の情報を保持しておきます。 例えば、『C』の輪郭の情報の中に一つまえが『B』で次が『D』である事を保持しておきます。 この前後関係を保持しているのがシーケンス(CvSeq)だと思います。 (参考) http://opencv.jp/opencv-1.0.0/document/opencvref_cxcore_sequences.html#decl_CvSeq cvFindContoursの場合、3番目の引数(contour)に最初の輪郭情報のポインタが格納され、 contour = contour->h_next とすると、次の輪郭情報を参照する事ができます。 この辺は http://opencv.jp/opencv-2svn/c/drawing_functions.html のページのcvDrawContoursのサンプルを見ると比較的分かりやすいかと思います。 また、cvFindContoursの場合は輪郭の内側、外側の情報も構築できるのできるのですが、どのように取得するかはcvFindContoursの5番目の引数(mode)の設定で決まります。 modeをCV_RETR_TREEにすると、輪郭情報がツリー構造で取得する事が出来ます。 この場合、輪郭の内側の輪郭も取得できるので、その場合は contour = contour->v_next とする内側の輪郭を参照する事が出来ます。 つまり、現在の輪郭(contour)の一つ次の輪郭はh_next、一つ前の輪郭はh_prev、一つ内側の輪郭はv_next、一つ外側の輪郭はv_prev となっています。 (説明が分かりづらくてスイマセン) そして、coutourについての輪郭の座標などの取得方法はこんな感じ↓です。 //面積 double Area = fabs(cvContourArea(coutour, CV_WHOLE_SEQ)); //周囲長 double Perimeter = cvArcLength(coutour); //輪郭を構成する頂点座標を取得 for ( int i = 0; i < coutour->total; i++){ CvPoint *point = CV_GET_SEQ_ELEM (CvPoint, coutour, i); } という感じで参考になりますでしょうか?

michiko_20
質問者

補足

返事おそくなってしまい申し訳ありません! 回答ありがとうございました。 おかげさまでCvFindCountorsが何をやっているのかが理解できた気がします。 最後の輪郭を構成する頂点座標を取得するというCV_GET_SEQ_ELEMという関数についてですが 早速使ってみたのですが、これは輪郭を構成する辺の座標という事なのでしょうか。 輪郭を構成する角点(特徴点?)の座標のみを抽出してくれる関数というのはないのでしょうか。

関連するQ&A

  • OpenCVを使った画像の切り抜き

    添付画像のように、サイズ(X,Y)の画像があったとします。 その画像のある座標(X',Y')とサイズを指定してできた短形領域を、IplImageとして保存するにはどうすればいいのでしょうか? OpenCVを使ってるのですが、そういった関数はなかったでしょうか? よろしくお願いします。

  • OpenCVを使って画像のノイズ除去を考えています

    OpenCVを使って画像のノイズ除去を考えています。 ですが、プログラムで上手く動いてくれないところがあり、分からなくて困っています。 もしわかる方がいらっしゃれば是非教えてください。 OpenCV2.4.6,VisualC++2010を用いています。 OpenCVを使わないLabeling.hなどを使った似たようなプログラムを教えてくださっても構いません。 ただ、Labeling.h自体がよくわからなく、Labeling.hを使って書いたプログラムが動かない状態であり、OpenCVの方がまだわかるので今回はOpenCVで質問しました。 プログラム(OpenCVを使った)の詳しい説明です。 入力画像の黒い点すべてがノイズだとします。またノイズのサイズは500以下だとします。 またサイズは特に指定はありません。拡張子は24bitのbmpを使っています。 画像の左側が入力画像とした時、画像の右側のように出力されます。(画像では分かりやすいように画像の切れ目を青の枠で囲っています。) 出力画像のふち?の部分が1ピクセルの範囲だけノイズ除去されずに残ってしまいます。(画像では分かりずらいですが赤の矢印の先の部分です。) 画像の下側のように赤のふち?1ピクセルの範囲はノイズ除去されません。 原因を考えているのですが、自分では分からなく困っています。 もしわかる方がいらっしゃれば是非教えてください。 私自身、プログラムは大学の授業レベル、OpenCVは使い始めて数ヶ月なので詳しくないです。 よろしくお願いします。 プログラムの内容は以下のようになっています。 〇〇〇は入力画像のファイル指定先 ●●●は出力画像のファイル指定先 ノイズのサイズは500以下とします。 自分は輪郭追跡のcvPointの部分が怪しいと考えてます。 今書いてるプログラムから一部抜き出してきたのでもしかしたら余計な処理が入っているかもしれません。 一応コピペでライブラリの設定、入力・出力画像のファイル指定をしていただくと動くと思います。 #include "stdafx.h" #include <stdio.h> #include "opencv/cv.h" #include "opencv/highgui.h" int _tmain(int argc, _TCHAR* argv[]) { IplImage *Proc;//処理画像 int i; char input_fname[256]; //元画像読み込み先 char output_fname[256]; //処理後画像出力先 //輪郭情報 CvMemStorage* Storage;//メモリストレージ CvSeq* Contours=0;//輪郭データ int Count=0;//輪郭の数 double Area=0;//面積 Storage=cvCreateMemStorage(0);//メモリストレージを確保 sprintf(input_fname, "〇〇〇"); sprintf(output_fname, "●●●"); IplImage *Input = cvLoadImage( input_fname, CV_LOAD_IMAGE_GRAYSCALE); if( Input == NULL ){ printf("ファイルが読み込めません。\n"); cvWaitKey(0); // キー入力待機 return -1; } // (1)二値化(大津の手法を利用) cvThreshold (Input, Input, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);//大津の二値化を用いて色を反転させる Proc = cvCreateImage(cvGetSize(Input), Input->depth, 1);//処理画像 cvCopy(Input,Proc,NULL); //輪郭を取得 Count = cvFindContours(Proc,Storage,&Contours,sizeof(CvContour),CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); //輪郭情報の取得 for(i=1;i<=Count;i++){ Area=abs(cvContourArea(Contours));//面積 if(Area<500){//面積が500以下の場合、黒で塗りつぶす cvDrawContours( Input, Contours, CV_RGB(0,0,0),CV_RGB(0,0,0), 0, CV_FILLED);} Contours=Contours->h_next;//次の輪郭へ } cvThreshold (Input, Input, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);//大津の二値化を用いて色を反転させる cvSaveImage(output_fname,Input);//矩形描画した画像を保存 //画像情報解放 cvReleaseImage(&Input); cvReleaseImage(&Proc); }

  • opencvの練習

    今、練習でhttp://gihyo.jp/dev/feature/01/opencv/0004こちらのオブジェクト検出器を練習しているのですが 1>------ ビルド開始: プロジェクト: 練習, 構成: Debug Win32 ------ 1>gihyo.obj : error LNK2019: 未解決の外部シンボル _cvReleaseHaarClassifierCascade が関数 _main で参照されました。 1>gihyo.obj : error LNK2019: 未解決の外部シンボル _cvHaarDetectObjects が関数 _main で参照されました。 1>C:\Documents and Settings\ユーザー名\デスクトップ\練習2\Debug\練習2.exe : fatal error LNK1120: 外部参照 2 が未解決です。 ========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ========== エラーが出てしまって先に進めません。 何が悪いのか教えてください。 よろしくお願いします。 プログラムは #include "cv.h" #include "ml.h" #include "highgui.h" int main(int argc, char* argv[]) { /* 画像のロード */ char imgfile[] = "Test/IMG_0532.jpg"; IplImage* image = cvLoadImage( imgfile, 1 ); /* オブジェクトのロード */ CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( "gihyo_basic2.xml" ); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* objs; int i; /* オブジェクト検出 */ objs = cvHaarDetectObjects( image, cascade, storage, 1.15, 2, CV_HAAR_DO_CANNY_PRUNING ); /* オブジェクト領域の描画 */ for( i = 0; i < objs->total; i++ ) { /* extract the rectanlges only */ CvRect obj_rect = *(CvRect*)cvGetSeqElem( objs, i ); cvRectangle( image, cvPoint(obj_rect.x,obj_rect.y), cvPoint((obj_rect.x+obj_rect.width), (obj_rect.y+obj_rect.height)), CV_RGB(255,0,0), 3 ); } /* 画像の表示 */ cvReleaseMemStorage( &storage ); cvNamedWindow ("result", CV_WINDOW_AUTOSIZE); cvShowImage( "result", image ); cvWaitKey(0); cvDestroyWindow("result"); cvReleaseHaarClassifierCascade( &cascade ); /* 結果の保存 */ cvSaveImage("result1.jpg", image); cvReleaseImage( &image ); return 0; }

  • OpenCV輪郭抽出→座標取得でのバグ(C++)

    プログラミング初心者の者です。 今OpenCVを色々勉強してるのですが、全く行き詰ってしまいました。 サンプルを打ち込んだりして、輪郭抽出、表示まではできましたが、それに加えて座標の取得、表示の部分を書いてみたんですが、バグが一向に取れません。 OpenCV2.4.1 Visual Studio2010ExpressC++でやっています。 0x00411845 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00000004 を読み込み中にアクセス違反が発生しました。 という内容が表示されます。 以下のようなコードを書きました。 おかしいところもたくさんあると思いますが、何卒ご教示頂ければと思います。 using namespace cv; using namespace std; int i; IplImage *g_image = NULL; IplImage *g_gray = NULL; IplImage *src_img = NULL; IplImage *tmp_img = NULL; int g_thresh = 100;//閾値 CvMemStorage *g_storage = NULL;//データ格納用低レベル構造体 CvFileStorage *fs;//ファイルストレッジ CvTreeNodeIterator it;//イテレータ CvPoint *point,*tmp; void on_trackbar(int){ if( g_storage == NULL ){ g_gray = cvCreateImage( cvGetSize( g_image ), 8, 1 ); g_storage = cvCreateMemStorage(0); } else { cvClearMemStorage( g_storage ); } CvSeq* contours = 0; cvCvtColor( g_image, g_gray, CV_BGR2GRAY ); cvThreshold( g_gray, g_gray, g_thresh, 255, CV_THRESH_BINARY ); cvFindContours( g_gray, g_storage, &contours,sizeof(CvContour ),CV_RETR_TREE,CV_CHAIN_APPROX_NONE); //輪郭抽出 (入力画像、保存先、一番外の輪郭、サイズ、  ) 抽出モード cvZero( g_gray ); if( contours ){ cvDrawContours( g_gray, contours, cvScalarAll(255), cvScalarAll(255), 100 ); } cvInitTreeNodeIterator (&it, contours,1); fs=cvOpenFileStorage("Contours.xml",NULL,CV_STORAGE_WRITE); //輪郭線上を走査 while((contours=(CvSeq*)cvNextTreeNode(&it))!=NULL){ cvClearMemStorage( g_storage ); cvStartWriteStruct(fs,"Contours",CV_NODE_SEQ); for (i=0;i<contours->total;i++){ point=CV_GET_SEQ_ELEM(CvPoint,contours,i); cvLine(g_gray,*tmp,*point,CV_RGB(0,0,255),2); cvStartWriteStruct(fs,NULL,CV_NODE_MAP); cvWriteInt(fs,"x",point->x); cvWriteInt(fs,"y",point->y); //座標取得 cvEndWriteStruct(fs); tmp=point; } cvEndWriteStruct(fs); cvReleaseFileStorage(&fs); } cvShowImage( "Contours", g_gray ); } int _tmain(int argc, _TCHAR* argv[]){ g_image = cvLoadImage( "C:\\OpenCV2.4.1\\opencv\\samples\\c\\lena.jpg" ); //入力画像       cvNamedWindow( "Contours", 1 ); cvCreateTrackbar( "Threshold", "Contours", &g_thresh, 255, on_trackbar ); on_trackbar(0); cvWaitKey(); return 0; }

  • 一般化座標と時間

    3次元でN個の質点の一般化座標  {q_i}; (q_1,q_2,q_3),…,(q_3N-2,q_3N-1,q_3N)  (1) とし、デカルト座標系でも同様に  {x_i}; (x_1,x_2,x_3),…,(x_3N-2,x_3N-1,x_3N)  (2) と表すとする。 運動をデカルト座標で表す場合も一般化座標で表す場合も、3N個の独立変数が存在し、両者の間に  x_i = x_i(q_1,…,q_3N)  (3)  q_i = q_i(x_1,…,x_3N)  (4) という交換関係が成り立つ。 運動が時間に直接依存する束縛条件の下で行われる場合や、座標系が時間とともに動く運動座標系の場合は  x_i = x_i(q_1,…,q_3N,t)  (5)  q_i = q_i(x_1,…,x_3N,t)  (6) のように、座標の間の関係は一般には陽に時間tを含むことになり、∂x_i/∂tなどがゼロにならないことを注意しておく。 と解析力学の本に書いてあるのですが、いろいろ疑問があります。 i) (3)(4)で、なぜx_iがq_1~q_3N全ての関数となるのでしょうか?(1)(2)を考えると、x_iが属する質点を表す3つqだけに拠るのではないかと思うのですが…。 ii) (5)(6)ではtが明示的に関数の引数に加えられていますが、運動というものを考える上では必ず時間の概念があると思うのですが、そうなると(3)(4)とはどのような違いがあるのでしょうか?「陽に時間を含む」とはどういうことなのか改めて教えて下さい。 iii) 「∂x_i/∂tなどがゼロにならない」とありますが、ii)にも書いたように時間に関係ない運動はないのだから、時間で偏微分して0になるというのはどういうことなのでしょうか?質点がずっと静止しているという意味じゃないですよね…? iv) 時間での全微分と偏微分の違いがわかりません。 膨大で申し訳ありません。一部でもよいのでご回答頂ければと思います。よろしくお願いします。

  • 抽出した特徴点の座標を取得したいのですが…

    OpenCVの特徴点を抽出するサンプルプログラム http://opencv.jp/sample/gradient_edge_corner.html#goodfeaturesを使用して, 特徴点の座標をx,y座標として取得したいと思っているのですが, 関数cvFindCornerSubPix()の2番目の引数cornersに, 「コーナーの初期座標が入力され,高精度化された座標が出力される」 とあったので,出力してみたところ,5~6桁の数字がズラーッと表示されました. この数字が高精度化された座標なのでしょうが, 特徴点座標をx,y座標として取得する方法はないのでしょうか? ご存知の方がいらっしゃれば,ご教授いただけると幸いです. よろしくお願いいたします.

  • ベッセル関数

    円筒座標系での電磁場のマクスウェル方程式を磁場に関して解いて得られる解が複素数を引数とする0次のベッセル関数 AJ0(kr)、kが複素数、Aは実係数、rは実変数 で得られるのですが 引数を実数に変換する方法がわかりません。 純虚数の引数であれば実数の引数の変形ベッセル関数に変換でき、 実数の引数であれば手持ちの本にベッセル関数の値が載っているのですが 複素数の引数の場合の処理方法がわからなくて困っています。 よろしくお願いします。

  • コマンドライン引数のワイルドカード指定

    以下のように、Javaで作成したプログラムを起動するとします。 >java sample *.java このとき、カレントディレクトリの拡張子が".java"というファイル N個をmain関数の引数に渡すようなことは可能でしょうか? わかりにくい質問で申し訳ありません。

    • ベストアンサー
    • Java
  • 統計力学のある問題で分配関数を求めたとき、粒子は区別出来ないという設定

    統計力学のある問題で分配関数を求めたとき、粒子は区別出来ないという設定だったので全粒子数Nの階乗で割るという操作をしていました。 N個の粒子の並べ方/N!=N個の粒子の組み合わせ ということは理解できるのですが、 粒子を区別する分配関数/N!=粒子を区別しない分配関数 となるのはいまいち理解出来ません。この辺についての解説をよろしくお願いします。

  • func.arityで、undefined

    とほほのjavascriptで勉強しているのですが http://www.tohoho-web.com/js/function.htm 関数オブジェクトのfunc.arityのところ 関数が要求する引数の個数を返します。 とあるのに、 function goukei(a, b, c) { return(a + b + c); } n = goukei.arity; document.write(n); このコードを書いて実行しても 引数の個数の3ではなく、undefinedが表示されます。 ちゃんと引数は3個だし、functionで定義した関数も、document.write文の前に宣言してあり ぱっとみ問題ないように思われるのですが、どうしてundefinedと表示されるのでしょうか。