特徴検出 ============ .. highlight:: c .. index:: Canny .. _Canny: Canny ----- `id=0.648283361295 Comments from the Wiki `__ .. cfunction:: void cvCanny( const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3 ) エッジ検出のための Canny アルゴリズムを実行します. :param image: シングルチャンネルの入力画像. :param edges: シングルチャンネルの出力画像,この関数によって検出されたエッジが格納されます. :param threshold1: 1 番目の閾値. :param threshold2: 2 番目の閾値. :param aperture_size: Sobelオペレータのアパーチャサイズ( :ref:`Sobel` を参照してください). この関数は,Canny アルゴリズムを用いて入力画像 ``image`` 中のエッジを検出し,出力画像 ``edges`` 上に記録します. ``threshold1`` と ``threshold2`` の内,小さい方の値はエッジ同士の接続に利用され,大きい方の値は強いエッジの初期検出に利用されます. .. index:: CornerEigenValsAndVecs .. _CornerEigenValsAndVecs: CornerEigenValsAndVecs ---------------------- `id=0.838608192937 Comments from the Wiki `__ .. cfunction:: void cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv, int blockSize, int aperture_size=3 ) コーナー検出のための,画像の固有値と固有ベクトルを求めます. :param image: 入力画像. :param eigenvv: 結果を保存するための画像.入力画像の 6 倍の幅が必要です. :param blockSize: 近傍領域のサイズ(以下の説明を参照してください). :param aperture_size: Sobelオペレータのアパーチャサイズ( :ref:`Sobel` を参照してください). この関数では,まず各ピクセルに対して ``blockSize`` :math:`\times` ``blockSize`` の近傍領域 S(p) を考えます.そして,以下のように各近傍領域全体に対して導関数の共変動行列を求めます: .. math:: 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} この行列の固有ベクトルと固有値を求めて,出力画像に :math:`(\lambda_1, \lambda_2, x_1, y_1, x_2, y_2)` の形式で保存します.ここで, * :math:`\lambda_1, \lambda_2` は, :math:`M` の固有値(ソートされていません), * :math:`x_1, y_1` は, :math:`\lambda_1` に対応する固有ベクトル, * :math:`x_2, y_2` は, :math:`\lambda_2` に対応する固有ベクトル です. .. index:: CornerHarris .. _CornerHarris: CornerHarris ------------ `id=0.369747941115 Comments from the Wiki `__ .. cfunction:: void cvCornerHarris( const CvArr* image, CvArr* harris_dst, int blockSize, int aperture_size=3, double k=0.04 ) Harris エッジ検出器. :param image: 入力画像. :param harris_dst: 検出結果を保存するための画像. ``image`` と同じサイズでなければいけません. :param blockSize: 近傍領域サイズ( :ref:`CornerEigenValsAndVecs` の説明を参照してください). :param aperture_size: Sobelオペレータのアパーチャサイズ( :ref:`Sobel` を参照してください). :param k: Harris 検出器のパラメータ.後述の式を参照してください. この関数は,入力画像に対して Harris エッジ検出を行います. :ref:`CornerMinEigenVal` や :ref:`CornerEigenValsAndVecs` と同様に,各ピクセルの :math:`\texttt{blockSize} \times \texttt{blockSize}` サイズの近傍領域全体に対して :math:`2\times2` の勾配共変動行列 :math:`M` が求められます. そして, .. math:: det(M) - k \, trace(M)^2 が出力画像に格納されます.入力画像中のコーナーは,出力画像における極大点として検出できます. .. index:: CornerMinEigenVal .. _CornerMinEigenVal: CornerMinEigenVal ----------------- `id=0.529571672473 Comments from the Wiki `__ .. cfunction:: void cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, int blockSize, int aperture_size=3 ) コーナー検出のための,勾配行列の最小固有値を求めます. :param image: 入力画像. :param eigenval: 最小固有値を保存するための画像. ``image`` と同じサイズでなければいけません. :param blockSize: 近傍領域サイズ( :ref:`CornerEigenValsAndVecs` の説明を参照してください). :param aperture_size: Sobelオペレータのアパーチャサイズ( :ref:`Sobel` を参照してください). この関数は,関数 :ref:`CornerEigenValsAndVecs` と似ていますが,これは各ピクセルに対して導関数の共変動行列の最小固有値のみを求めます.つまりそれは,前述の関数の :math:`min(\lambda_1, \lambda_2)` に相当します. .. index:: FindCornerSubPix .. _FindCornerSubPix: FindCornerSubPix ---------------- `id=0.857041398204 Comments from the Wiki `__ .. cfunction:: void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners, int count, CvSize win, CvSize zero_zone, CvTermCriteria criteria ) コーナー位置を高精度化します. :param image: 入力画像. :param corners: コーナーの初期座標が入力され,高精度化された座標が出力される変数. :param count: コーナーの総数. :param win: 探索窓の半分のサイズ.例えば, ``win`` =(5,5)の場合,5*2+1 :math:`\times` 5*2+1 = 11 :math:`\times` 11 サイズの探索窓が利用されます :param zero_zone: 探索領域の中心に存在する(後述の式において総和を計算する際に含まれない)対象外領域のサイズの半分.この値は,自己相関行列において発生しうる特異点を避けるために用いられます. 値が(-1,-1) の場合は,そのようなサイズはない,ということを意味します. :param criteria: コーナー位置高精度化のための繰り返し処理の停止基準.つまり,この繰り返し処理は,規定回数に達するか要求精度に達したときに停止します. ``criteria`` は,最大反復数と要求精度のどちらか,あるいは両方を指定します. この関数は,以下の図に示されるような,サブピクセル精度のコーナー,あるいは鞍点を検出するために繰り返し処理を行います. .. image:: ../../pics/cornersubpix.png サブピクセル精度のコーナー位置決めは,近傍領域の中心 :math:`q` から,その領域内に位置する点 :math:`p` に向かう各ベクトルが, :math:`p` における(画像自身と観測ノイズに従う)画像勾配と直交する,という考えに基づいています.これは,以下の式で表現されます: .. math:: \epsilon _i = {DI_{p_i}}^T \cdot (q - p_i) ここで :math:`{DI_{p_i}}` は,近傍領域 :math:`q` 内の点 :math:`p_i` における画像勾配を表します. :math:`q` は,この :math:`\epsilon_i` を最小にする値として求められます. :math:`\epsilon_i` を 0 とすることで連立方程式が得られます: .. math:: \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) q = \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i) ここで,画像勾配は :math:`q` の近傍領域(「探索窓」)での総和をとられます.1次勾配を :math:`G` ,2次勾配を :math:`b` とすると,以下の関係が得られます: .. math:: q = G^{-1} \cdot b このアルゴリズムは,探索窓の中心をこの新しい値 :math:`q` に再設定し,値の変化量が与えられた閾値内に収まるようになるまで繰り返し計算を行います. .. index:: GoodFeaturesToTrack .. _GoodFeaturesToTrack: GoodFeaturesToTrack ------------------- `id=0.327412833903 Comments from the Wiki `__ .. cfunction:: 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 ) 画像内の強いコーナーを検出します. :param image: 8ビット,または32ビット浮動小数点型シングルチャンネルの入力画像. :param eigImage: 32ビット浮動小数点型のテンポラリ画像.サイズは ``image`` と同じです. :param tempImage: 別のテンポラリ画像.サイズ・フォーマットともに ``eigImage`` と同じです. :param corners: 出力パラメータ.検出されたコーナー. :param cornerCount: 出力パラメータ.検出されたコーナーの数. :param qualityLevel: 最大固有値,最小固有値に乗ずる定数.これは,検出される画像コーナーの許容最低品質を指定します. :param minDistance: 検出されるコーナー間の許容最小距離.ユークリッド距離が用いられます. :param mask: ROI.関数は,この指定領域内から点を選択しますが,NULL ならば画像全体から選択します. :param blockSize: 平均化ブロックサイズ.この関数内部で利用される :ref:`CornerMinEigenVal` や :ref:`CornerHarris` に渡される値です. :param useHarris: 0でない場合は,デフォルトの :ref:`CornerMinEigenVal` の代わりに Harris オペレータ( :ref:`CornerHarris` )が利用されます. :param k: Harris 検出器のパラメータ. ( :math:`\texttt{useHarris} != 0` ) の場合にのみ用いられます. この関数は,与えられた画像から大きな固有値を持つコーナーを検出します.これはまず,関数 :ref:`CornerMinEigenVal` を利用して入力画像の各ピクセルに対する最小固有値を計算し,それを ``eigImage`` に格納します.そして,non-maxima suppression を行います( :math:`3\times 3` の近傍領域内において,その極大値のみが残ります).次に, :math:`\texttt{qualityLevel} \cdot max(\texttt{eigImage}(x,y))` よりも小さな固有値を持つコーナーを棄却します.最後に,あらゆる2つのコーナー同士の距離が ``minDistance`` よりも小さくならないようにします.これによって,強い方のコーナーに近すぎる,弱い方のコーナー(最小固有値が小さいコーナー)が削除されます. この関数が,パラメータ ``qualityLevel`` に異なる値 ``A`` と ``B`` を与えられて呼び出され,その時に ``A`` > {B} であるとします.その場合,出力コーナー配列において ``qualityLevel=A`` で求められたコーナーの配列が, ``qualityLevel=B`` で求められたものよりも前に位置することに注意してください. .. index:: HoughLines2 .. _HoughLines2: HoughLines2 ----------- `id=0.582151272744 Comments from the Wiki `__ .. cfunction:: CvSeq* cvHoughLines2( CvArr* image, void* storage, int method, double rho, double theta, int threshold, double param1=0, double param2=0 ) ハフ変換を用いて,2値画像から直線を検出します. :param image: 入力画像.8ビット,シングルチャンネル,2値.確率的手法の場合は,この画像は関数により書き換えられます. :param storage: 検出された線を保存するストレージ.これは,メモリストレージ(この場合,ストレージ内に線のシーケンスが作成され,そのポインタがこの関数によって返されます),あるいは,線のパラメータが書き込まれる特定の型(後述の説明を参照してください)を持つ1列あるいは1行の行列(CvMat*)です.その行列のヘッダの ``cols`` や ``rows`` は,検出された線の個数を表すようにこの関数によって書き換えられます.また, ``storage`` が行列であり,かつ実際の線の個数が行列のサイズを越えていた場合,行列に収まる線の最大数が返されます(標準的ハフ変換の場合,線は投票数によってソートされます). :param method: ハフ変換のバリエーション,以下のうちの1つが指定されます: * **CV_HOUGH_STANDARD** 古典的,あるいは標準的ハフ変換.各直線は,2つの浮動小数点数 :math:`(\rho, \theta)` で表現されます.ここで, :math:`\rho` は点(0,0)から直線までの距離, :math:`\theta` はx軸と直線の法線が成す角度を表します.したがって,行列のデータは必ず ``CV_32FC2`` 型でなければいけません(作成されるシーケンスもそうなります). * **CV_HOUGH_PROBABILISTIC** 確率的ハフ変換(数本の長い線分を含むだけの写真の場合に,より効率的です).この場合,関数は直線全体ではなく線分を返します.各線分は始点と終点で表現されるので,行列のデータは必ず ``CV_32SC4`` 型でなければいけません(作成されるシーケンスもそうなります). * **CV_HOUGH_MULTI_SCALE** 古典的ハフ変換のマルチスケール版.直線は, ``CV_HOUGH_STANDARD`` の場合と同じようにエンコードされます. :param rho: ピクセルに依存した単位で表される距離分解能. :param theta: ラジアン単位で表される角度分解能. :param threshold: 閾値パラメータ.その投票数がこの ``threshold`` よりも大きい線のみが返されます. :param param1: 手法依存の 1 番目のパラメータ: * 古典的ハフ変換では使用されません (0). * 確率的ハフ変換では,線分長の最小値を表します. * マルチスケールハフ変換では,距離分解能 :math:`\rho` に対する除数を表します(粗い分解能は :math:`\rho` となり,細かい分解能は :math:`(\rho / \texttt{param1})` となります). :param param2: 手法依存の 2 番目のパラメータ: * 古典的ハフ変換では使用されません (0). * 確率的ハフ変換では,同一線上に存在する線分として扱うための(つまり,それらを統合しても問題ない),2つの線分間距離の最大値を表します. * マルチスケールハフ変換では,角度分解能 :math:`\theta` に対する除数を表します(粗い分解能は :math:`\theta` となり,細かい分解能は :math:`(\theta / \texttt{param2})` となります). この関数は,線を検出するハフ変換のいくつかのバリエーションの実装です. **Example. Detecting lines with Hough transform.** .. code-block:: c /* これは,単独で動作するプログラムである.プログラムの最初の引数として画像名を渡します. "#if 1" を "#if 0" に変更したり戻したりすることで, 標準的ハフ変換と確率的ハフ変換を切り替えることができます. */ #include #include #include 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); } } .. サンプル画像.上記のプログラムはこの画像用にパラメータを調整しています: .. image:: ../../pics/building.jpg 上記のプログラムにおいて確率的ハフ変換を行った( ``#if 0`` の場合)結果: .. image:: ../../pics/houghp.png .. index:: PreCornerDetect .. _PreCornerDetect: PreCornerDetect --------------- `id=0.759447754297 Comments from the Wiki `__ .. cfunction:: void cvPreCornerDetect( const CvArr* image, CvArr* corners, int apertureSize=3 ) コーナー検出のための特徴マップを求めます. :param image: 入力画像. :param corners: コーナー候補を保存するための画像. :param apertureSize: Sobelオペレータのアパーチャサイズ( :ref:`Sobel` を参照してください). この関数は,以下の関数を計算します. .. math:: D_x^2 D_{yy} + D_y^2 D_{xx} - 2 D_x D_y D_{xy} ここで, :math:`D_?` は1次微分画像, :math:`D_{??}` は2次微分画像を表します. コーナーは,以下のように関数の極大点として計算できます: .. code-block:: c // 浮動小数点型の画像であるとします. 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 ); .. .. index:: SampleLine .. _SampleLine: SampleLine ---------- `id=0.0688128398409 Comments from the Wiki `__ .. cfunction:: int cvSampleLine( const CvArr* image CvPoint pt1 CvPoint pt2 void* buffer int connectivity=8 ) ラスタ表現された線分を読み込み,バッファに書き込みます. :param image: 線分をサンプリングするための入力画像. :param pt1: 線分の始点. :param pt2: 線分の終点. :param buffer: 線分上の点を保存するバッファ.十分なサイズが必要で,8連結の線分の場合は, :math:`max( |\texttt{pt2.x} - \texttt{pt1.x}|+1, |\texttt{pt2.y} - \texttt{pt1.y}|+1 )` 個,4連結の線分の場合は, :math:`(|\texttt{pt2.x}-\texttt{pt1.x}|+|\texttt{pt2.y}-\texttt{pt1.y}|+1)` 個の点を保存できなければいけません. :param connectivity: 線分の接続性,4連結,あるいは8連結. この関数は,ラインイテレータの応用の一種です.これは, ``pt1`` と ``pt2`` を結ぶ線上にある画像ピクセル(終点を含みます)をすべて読み込み,それをバッファに格納します.