最終更新:
mikk_ni3_92 2010年02月10日(水) 18:59:19履歴
現在地 >> メニュー >> OpenCV >> sequence編02
INDEX:sequence編01<< sequence編02 >> sequence編03
【例】
ハフ変換による円の検出を行う時には、cvHoughCircles関数を使う。
INDEX:sequence編01<< sequence編02 >> sequence編03
ハフ変換の詳細は略。(codezine:javaを使った丁寧な説明をされております)
ただ、次の事は覚えておきたい。
直線検出には「cvHoughLines2関数」を使う。
このシーケンスからデータを取り出して、画像に直線を引いたりする。
ただ、次の事は覚えておきたい。
- (x, y)を通過する全ての直線群は、一本のHough曲線で表される。
- パラメータ平面上の一点は、直線一本に対応する。
![]() | ![]() |
直線検出には「cvHoughLines2関数」を使う。
CvSeq* cvHoughLines2( CvArr* image, void* line_storage, int method, double rho, double theta, int threshold, double param1=0, double param2=0) [image]:1チャネルの2値画像。なおかつ深度は8bit。 [line_storage]:保存先にするメモリストレージ [method]:使用するハフ変換の種類 CV_HOUGH_STANDARD → 標準(CV_32FC2のデータを使う) CV_HOUGH_PROBABILISTIC → 確率的ハフ変換(CV_32SC4のデータを使う) CV_HOUGH_MULTI_SCALE → マルチスケールハフ変換(標準型と同じ) [rho、theta]:「ピクセル単位での距離分解能」と「ラジアン単位で表される角度分解能」 [threshold]:閾値。これより大きい投票数のものが直線となる。 [param1]:略。(リファレンス参照) [param2]:略。(リファレンス参照)▲返り値は検出した直線のシーケンス。
このシーケンスからデータを取り出して、画像に直線を引いたりする。
- メモリストレージ、シーケンスの用意。
- 画像をCannyエッジオペレータ等で2値化。
- ハフ変換
- 検出した直線を格納したシーケンスを使って処理をする。
【例】
IplImage *imgA = cvLoadImage(filename,0); … … cvCanny(imgA,imgA,10,50); //メモリストレージとシーケンスを用意 CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* lines = 0; //ハフ変換による直線の検出 lines = cvHoughLines2( imgA,storage,CV_HOUGH_STANDARD,1,CV_PI/180,100,0,0 ); … …
得られるのはあくまでも(ρ,θ)である。
float *line; float rho,theta; CvPoint pt1, pt2; double x0,y0; for(int loop = 0; loop < lines->total;++loop) { //ρとθの取り出し line = reinterpret_cast<float *>( cvGetSeqElem(lines,loop) ); rho = line[0]; theta = line[1]; //ρとθから座標直線を通過するある点を取得 x0 = rho * cosf(theta); y0 = rho * sinf(theta); //注目点からのある量だけ移動した2点を取得 pt1 = cvPoint( cvRound(x0 + 1000*(-sinf(theta) ) ), cvRound(y0 + 1000*( cosf(theta) ) ) ); pt2 = cvPoint( cvRound(x0 - 1000*(-sinf(theta) ) ), cvRound(y0 - 1000*( cosf(theta) ) ) ); … … }
確率的ハフ変換である「CV_HOUGH_PROBABILISTIC」を指定した時は、
「CV_32SC4」がシーケンスに格納される。
「CV_32SC4」がシーケンスに格納される。
IplImage *imgA = cvLoadImage(filename,0); … … //メモリストレージとシーケンスを用意 CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* lines = 0; //ハフ変換による直線の検出(確率的) lines = cvHoughLines2( imgA,storage,CV_HOUGH_PROBABILISTIC,1,CV_PI/180,80,30,10 ); IplImage *imgA_out = cvCreateImage(cvGetSize(imgA),IPL_DEPTH_8U,3); cvCvtColor(imgA,imgA_out,CV_GRAY2RGB);//直線描画用 CvPoint *line; for(int loop = 0; loop < MIN(lines->total,100);++loop) { line = reinterpret_cast<CvPoint *>( cvGetSeqElem(lines,loop) ); cvLine(imgA_out, line[0], line[1], CV_RGB(255,0,0), 3, 8 ); } cvNamedWindow("CV_HOUGH_PROBABILISTIC"); cvShowImage("CV_HOUGH_PROBABILISTIC",imgA_out);
- sequence編02::まとめ1(CV_HOUGH_STANDARD)
- sequence編02::まとめ2(CV_HOUGH_PROBABILISTIC)
ハフ変換による円の検出を行う時には、cvHoughCircles関数を使う。
CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1 CV_DEFAULT(100), double param2 CV_DEFAULT(100), int min_radius CV_DEFAULT(0), int max_radius CV_DEFAULT(0) ) 【image】:8bitグレイスケール画像。2値画像の必要はない。 【circle_storage】:検出した円を格納するシーケンス。(CV_32FC3のデータが格納されていく) 【method】:「CV_HOUGH_GRADIENT」を指定する 【dp】:画像分解能に対する投票分解能の比率の逆数(1を指定するとそのまま。2 の場合は,投票空間の幅と高さは半分...etc) 【min_dist】:検出される円の中心同士の最小距離 【param1、param2】:Canny エッジに渡される大きい方の閾値/円の中心を検出する際の投票数の閾値 【 min_radius/max_radius】:円の半径の最小値/最大値
円の検出で得られるデータは、円の中心座標と半径である。
IplImage *imgA = cvLoadImage(filename,0); … … CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* circles = 0; //ハフ変換による円の検出 circles = cvHoughCircles(imgA,storage,CV_HOUGH_GRADIENT,1,imgA->width/10); IplImage *imgA_out = cvCreateImage(cvGetSize(imgA),IPL_DEPTH_8U,3); cvCvtColor(imgA,imgA_out,CV_GRAY2RGB);//直線描画用 float *circle;//(x,y,r)がくる CvPoint pt; for(int loop = 0; loop < circles->total;++loop) { circle = reinterpret_cast<float *>(cvGetSeqElem(circles,loop)); pt = cvPoint(cvRound(circle[0]),cvRound(circle[1]));//中心座標(x,y)を取得 cvCircle(imgA_out,pt,cvRound(circle[2]),CV_RGB(255,0,0),2);//円として検出したものを描画 } cvNamedWindow("cvHoughCircles"); cvShowImage("cvHoughCircles",imgA_out);
- sequence編02::まとめ3(ハフ変換の円検出)