特徴検出

Canny

Comments from the Wiki

void cvCanny(const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3)

エッジ検出のための Canny アルゴリズムを実行します.

パラメタ:
  • image – シングルチャンネルの入力画像.
  • edges – シングルチャンネルの出力画像,この関数によって検出されたエッジが格納されます.
  • threshold1 – 1 番目の閾値.
  • threshold2 – 2 番目の閾値.
  • aperture_size – Sobelオペレータのアパーチャサイズ( Sobel を参照してください).

この関数は,Canny アルゴリズムを用いて入力画像 image 中のエッジを検出し,出力画像 edges 上に記録します. threshold1threshold2 の内,小さい方の値はエッジ同士の接続に利用され,大きい方の値は強いエッジの初期検出に利用されます.

CornerEigenValsAndVecs

Comments from the Wiki

void cvCornerEigenValsAndVecs(const CvArr* image, CvArr* eigenvv, int blockSize, int aperture_size=3)

コーナー検出のための,画像の固有値と固有ベクトルを求めます.

パラメタ:
  • image – 入力画像.
  • eigenvv – 結果を保存するための画像.入力画像の 6 倍の幅が必要です.
  • blockSize – 近傍領域のサイズ(以下の説明を参照してください).
  • aperture_size – Sobelオペレータのアパーチャサイズ( Sobel を参照してください).

この関数では,まず各ピクセルに対して blockSize \times blockSize の近傍領域 S(p) を考えます.そして,以下のように各近傍領域全体に対して導関数の共変動行列を求めます:

M =  \begin{bmatrix} \sum _{S(p)}(dI/dx)^2 &  \sum _{S(p)}(dI/dx  \cdot dI/dy)^2  \\ \sum _{S(p)}(dI/dx  \cdot dI/dy)^2 &  \sum _{S(p)}(dI/dy)^2 \end{bmatrix}

この行列の固有ベクトルと固有値を求めて,出力画像に (\lambda_1, \lambda_2, x_1, y_1, x_2, y_2) の形式で保存します.ここで,

  • \lambda_1, \lambda_2

    は, M の固有値(ソートされていません),

  • x_1, y_1

    は, \lambda_1 に対応する固有ベクトル,

  • x_2, y_2

    は, \lambda_2 に対応する固有ベクトル

です.

CornerHarris

Comments from the Wiki

void cvCornerHarris(const CvArr* image, CvArr* harris_dst, int blockSize, int aperture_size=3, double k=0.04)

Harris エッジ検出器.

パラメタ:
  • image – 入力画像.
  • harris_dst – 検出結果を保存するための画像. image と同じサイズでなければいけません.
  • blockSize – 近傍領域サイズ( CornerEigenValsAndVecs の説明を参照してください).
  • aperture_size – Sobelオペレータのアパーチャサイズ( Sobel を参照してください).
  • k – Harris 検出器のパラメータ.後述の式を参照してください.

この関数は,入力画像に対して Harris エッジ検出を行います. CornerMinEigenValCornerEigenValsAndVecs と同様に,各ピクセルの \texttt{blockSize} \times \texttt{blockSize} サイズの近傍領域全体に対して 2\times2 の勾配共変動行列 M が求められます. そして,

det(M) - k  \, trace(M)^2

が出力画像に格納されます.入力画像中のコーナーは,出力画像における極大点として検出できます.

CornerMinEigenVal

Comments from the Wiki

void cvCornerMinEigenVal(const CvArr* image, CvArr* eigenval, int blockSize, int aperture_size=3)

コーナー検出のための,勾配行列の最小固有値を求めます.

パラメタ:
  • image – 入力画像.
  • eigenval – 最小固有値を保存するための画像. image と同じサイズでなければいけません.
  • blockSize – 近傍領域サイズ( CornerEigenValsAndVecs の説明を参照してください).
  • aperture_size – Sobelオペレータのアパーチャサイズ( Sobel を参照してください).

この関数は,関数 CornerEigenValsAndVecs と似ていますが,これは各ピクセルに対して導関数の共変動行列の最小固有値のみを求めます.つまりそれは,前述の関数の min(\lambda_1, \lambda_2) に相当します.

FindCornerSubPix

Comments from the Wiki

void cvFindCornerSubPix(const CvArr* image, CvPoint2D32f* corners, int count, CvSize win, CvSize zero_zone, CvTermCriteria criteria)

コーナー位置を高精度化します.

パラメタ:
  • image – 入力画像.
  • corners – コーナーの初期座標が入力され,高精度化された座標が出力される変数.
  • count – コーナーの総数.
  • win – 探索窓の半分のサイズ.例えば, win =(5,5)の場合,5*2+1 \times 5*2+1 = 11 \times 11 サイズの探索窓が利用されます
  • zero_zone – 探索領域の中心に存在する(後述の式において総和を計算する際に含まれない)対象外領域のサイズの半分.この値は,自己相関行列において発生しうる特異点を避けるために用いられます. 値が(-1,-1) の場合は,そのようなサイズはない,ということを意味します.
  • criteria – コーナー位置高精度化のための繰り返し処理の停止基準.つまり,この繰り返し処理は,規定回数に達するか要求精度に達したときに停止します. criteria は,最大反復数と要求精度のどちらか,あるいは両方を指定します.

この関数は,以下の図に示されるような,サブピクセル精度のコーナー,あるいは鞍点を検出するために繰り返し処理を行います.

_images/cornersubpix.png

サブピクセル精度のコーナー位置決めは,近傍領域の中心 q から,その領域内に位置する点 p に向かう各ベクトルが, p における(画像自身と観測ノイズに従う)画像勾配と直交する,という考えに基づいています.これは,以下の式で表現されます:

\epsilon _i = {DI_{p_i}}^T  \cdot (q - p_i)

ここで {DI_{p_i}} は,近傍領域 q 内の点 p_i における画像勾配を表します. q は,この \epsilon_i を最小にする値として求められます. \epsilon_i を 0 とすることで連立方程式が得られます:

\sum _i(DI_{p_i}  \cdot {DI_{p_i}}^T) q =  \sum _i(DI_{p_i}  \cdot {DI_{p_i}}^T  \cdot p_i)

ここで,画像勾配は q の近傍領域(「探索窓」)での総和をとられます.1次勾配を G ,2次勾配を b とすると,以下の関係が得られます:

q = G^{-1}  \cdot b

このアルゴリズムは,探索窓の中心をこの新しい値 q に再設定し,値の変化量が与えられた閾値内に収まるようになるまで繰り返し計算を行います.

GoodFeaturesToTrack

Comments from the Wiki

void cvGoodFeaturesToTrack(const CvArr* image CvArr* eigImage, CvArr* tempImage CvPoint2D32f* corners int* cornerCount double qualityLevel double minDistance const CvArr* mask=NULL int blockSize=3 int useHarris=0 double k=0.04)

画像内の強いコーナーを検出します.

パラメタ:
  • image – 8ビット,または32ビット浮動小数点型シングルチャンネルの入力画像.
  • eigImage – 32ビット浮動小数点型のテンポラリ画像.サイズは image と同じです.
  • tempImage – 別のテンポラリ画像.サイズ・フォーマットともに eigImage と同じです.
  • corners – 出力パラメータ.検出されたコーナー.
  • cornerCount – 出力パラメータ.検出されたコーナーの数.
  • qualityLevel – 最大固有値,最小固有値に乗ずる定数.これは,検出される画像コーナーの許容最低品質を指定します.
  • minDistance – 検出されるコーナー間の許容最小距離.ユークリッド距離が用いられます.
  • mask – ROI.関数は,この指定領域内から点を選択しますが,NULL ならば画像全体から選択します.
  • blockSize – 平均化ブロックサイズ.この関数内部で利用される CornerMinEigenValCornerHarris に渡される値です.
  • useHarris – 0でない場合は,デフォルトの CornerMinEigenVal の代わりに Harris オペレータ( CornerHarris )が利用されます.
  • k – Harris 検出器のパラメータ. ( \texttt{useHarris} != 0 ) の場合にのみ用いられます.

この関数は,与えられた画像から大きな固有値を持つコーナーを検出します.これはまず,関数 CornerMinEigenVal を利用して入力画像の各ピクセルに対する最小固有値を計算し,それを eigImage に格納します.そして,non-maxima suppression を行います( 3\times 3 の近傍領域内において,その極大値のみが残ります).次に, \texttt{qualityLevel} \cdot max(\texttt{eigImage}(x,y)) よりも小さな固有値を持つコーナーを棄却します.最後に,あらゆる2つのコーナー同士の距離が minDistance よりも小さくならないようにします.これによって,強い方のコーナーに近すぎる,弱い方のコーナー(最小固有値が小さいコーナー)が削除されます.

この関数が,パラメータ qualityLevel に異なる値 AB を与えられて呼び出され,その時に A > {B} であるとします.その場合,出力コーナー配列において qualityLevel=A で求められたコーナーの配列が, qualityLevel=B で求められたものよりも前に位置することに注意してください.

HoughLines2

Comments from the Wiki

CvSeq* cvHoughLines2(CvArr* image, void* storage, int method, double rho, double theta, int threshold, double param1=0, double param2=0)

ハフ変換を用いて,2値画像から直線を検出します.

パラメタ:
  • image – 入力画像.8ビット,シングルチャンネル,2値.確率的手法の場合は,この画像は関数により書き換えられます.
  • storage – 検出された線を保存するストレージ.これは,メモリストレージ(この場合,ストレージ内に線のシーケンスが作成され,そのポインタがこの関数によって返されます),あるいは,線のパラメータが書き込まれる特定の型(後述の説明を参照してください)を持つ1列あるいは1行の行列(CvMat*)です.その行列のヘッダの colsrows は,検出された線の個数を表すようにこの関数によって書き換えられます.また, storage が行列であり,かつ実際の線の個数が行列のサイズを越えていた場合,行列に収まる線の最大数が返されます(標準的ハフ変換の場合,線は投票数によってソートされます).
  • method

    ハフ変換のバリエーション,以下のうちの1つが指定されます:

    • CV_HOUGH_STANDARD 古典的,あるいは標準的ハフ変換.各直線は,2つの浮動小数点数 (\rho, \theta) で表現されます.ここで, \rho は点(0,0)から直線までの距離, \theta はx軸と直線の法線が成す角度を表します.したがって,行列のデータは必ず CV_32FC2 型でなければいけません(作成されるシーケンスもそうなります).
    • CV_HOUGH_PROBABILISTIC 確率的ハフ変換(数本の長い線分を含むだけの写真の場合に,より効率的です).この場合,関数は直線全体ではなく線分を返します.各線分は始点と終点で表現されるので,行列のデータは必ず CV_32SC4 型でなければいけません(作成されるシーケンスもそうなります).
    • CV_HOUGH_MULTI_SCALE 古典的ハフ変換のマルチスケール版.直線は, CV_HOUGH_STANDARD の場合と同じようにエンコードされます.
  • rho – ピクセルに依存した単位で表される距離分解能.
  • theta – ラジアン単位で表される角度分解能.
  • threshold – 閾値パラメータ.その投票数がこの threshold よりも大きい線のみが返されます.
  • param1

    手法依存の 1 番目のパラメータ:

    • 古典的ハフ変換では使用されません (0).
    • 確率的ハフ変換では,線分長の最小値を表します.
    • マルチスケールハフ変換では,距離分解能 \rho に対する除数を表します(粗い分解能は \rho となり,細かい分解能は (\rho / \texttt{param1}) となります).
  • param2

    手法依存の 2 番目のパラメータ:

    • 古典的ハフ変換では使用されません (0).
    • 確率的ハフ変換では,同一線上に存在する線分として扱うための(つまり,それらを統合しても問題ない),2つの線分間距離の最大値を表します.
    • マルチスケールハフ変換では,角度分解能 \theta に対する除数を表します(粗い分解能は \theta となり,細かい分解能は (\theta / \texttt{param2}) となります).

この関数は,線を検出するハフ変換のいくつかのバリエーションの実装です.

Example. Detecting lines with Hough transform.

/* これは,単独で動作するプログラムである.プログラムの最初の引数として画像名を渡します.
   "#if 1" を "#if 0" に変更したり戻したりすることで,
   標準的ハフ変換と確率的ハフ変換を切り替えることができます.  */
#include <cv.h>
#include <highgui.h>
#include <math.h>

int main(int argc, char** argv)
{
    IplImage* src;
    if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0)
    {
        IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
        IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq* lines = 0;
        int i;
        cvCanny( src, dst, 50, 200, 3 );
        cvCvtColor( dst, color_dst, CV_GRAY2BGR );
#if 1
        lines = cvHoughLines2( dst,
                               storage,
                               CV_HOUGH_STANDARD,
                               1,
                               CV_PI/180,
                               100,
                               0,
                               0 );

        for( i = 0; i < MIN(lines->total,100); i++ )
        {
            float* line = (float*)cvGetSeqElem(lines,i);
            float rho = line[0];
            float theta = line[1];
            CvPoint pt1, pt2;
            double a = cos(theta), b = sin(theta);
            double x0 = a*rho, y0 = b*rho;
            pt1.x = cvRound(x0 + 1000*(-b));
            pt1.y = cvRound(y0 + 1000*(a));
            pt2.x = cvRound(x0 - 1000*(-b));
            pt2.y = cvRound(y0 - 1000*(a));
            cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
        }
#else
        lines = cvHoughLines2( dst,
                               storage,
                               CV_HOUGH_PROBABILISTIC,
                               1,
                               CV_PI/180,
                               80,
                               30,
                               10 );
        for( i = 0; i < lines->total; i++ )
        {
            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
            cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );
        }
#endif
        cvNamedWindow( "Source", 1 );
        cvShowImage( "Source", src );

        cvNamedWindow( "Hough", 1 );
        cvShowImage( "Hough", color_dst );

        cvWaitKey(0);
    }
}

サンプル画像.上記のプログラムはこの画像用にパラメータを調整しています:

_images/building.jpg

上記のプログラムにおいて確率的ハフ変換を行った( #if 0 の場合)結果:

_images/houghp.png

PreCornerDetect

Comments from the Wiki

void cvPreCornerDetect(const CvArr* image, CvArr* corners, int apertureSize=3)

コーナー検出のための特徴マップを求めます.

パラメタ:
  • image – 入力画像.
  • corners – コーナー候補を保存するための画像.
  • apertureSize – Sobelオペレータのアパーチャサイズ( Sobel を参照してください).

この関数は,以下の関数を計算します.

D_x^2 D_{yy} + D_y^2 D_{xx} - 2 D_x D_y D_{xy}

ここで, D_? は1次微分画像, D_{??} は2次微分画像を表します.

コーナーは,以下のように関数の極大点として計算できます:

// 浮動小数点型の画像であるとします.
IplImage* corners = cvCloneImage(image);
IplImage* dilated_corners = cvCloneImage(image);
IplImage* corner_mask = cvCreateImage( cvGetSize(image), 8, 1 );
cvPreCornerDetect( image, corners, 3 );
cvDilate( corners, dilated_corners, 0, 1 );
cvSubS( corners, dilated_corners, corners );
cvCmpS( corners, 0, corner_mask, CV_CMP_GE );
cvReleaseImage( &corners );
cvReleaseImage( &dilated_corners );

SampleLine

Comments from the Wiki

int cvSampleLine(const CvArr* image CvPoint pt1 CvPoint pt2 void* buffer int connectivity=8)

ラスタ表現された線分を読み込み,バッファに書き込みます.

パラメタ:
  • image – 線分をサンプリングするための入力画像.
  • pt1 – 線分の始点.
  • pt2 – 線分の終点.
  • buffer – 線分上の点を保存するバッファ.十分なサイズが必要で,8連結の線分の場合は, max( |\texttt{pt2.x} - \texttt{pt1.x}|+1, |\texttt{pt2.y} - \texttt{pt1.y}|+1 ) 個,4連結の線分の場合は, (|\texttt{pt2.x}-\texttt{pt1.x}|+|\texttt{pt2.y}-\texttt{pt1.y}|+1) 個の点を保存できなければいけません.
  • connectivity – 線分の接続性,4連結,あるいは8連結.

この関数は,ラインイテレータの応用の一種です.これは, pt1pt2 を結ぶ線上にある画像ピクセル(終点を含みます)をすべて読み込み,それをバッファに格納します.

目次

このページ