1. 程式人生 > >Opencv影象識別從零到精通(33)----moravec角點、harris角點

Opencv影象識別從零到精通(33)----moravec角點、harris角點

一、角點

    影象處理和與計算機視覺領域,興趣點(interest points),或稱作關鍵點(keypoints)、特徵點(feature points) 被大量用於解決物體識別,影象識別、影象匹配、視覺跟蹤、三維重建等一系列的問題。我們不再觀察整幅圖,而是選擇某些特殊的點,然後對他們進行區域性有的放矢的分析。如果能檢測到足夠多的這種點,同時他們的區分度很高,並且可以精確定位穩定的特徵,那麼這個方法就有使用價值。

影象特徵型別可以被分為如下三種:

        <1>邊緣                   <2>角點 (感興趣關鍵點)                 

<3>斑點(Blobs)(感興趣區域)

      其中,角點是個很特殊的存在。他們在影象中可以輕易地定位,同時,他們在人造物體場景,比如門、窗、桌等出隨處可見。因為角點位於兩條邊緣的交點處,代表了兩個邊緣變化的方向上的點,,所以他們是可以精確定位的二維特徵,甚至可以達到亞畫素的精度。且其影象梯度有很高的變化,這種變化是可以用來幫助檢測角點的。需要注意的是,角點與位於相同強度區域上的點不同,與物體輪廓上的點也不同,因為輪廓點難以在相同的其他物體上精確定位。

       角點檢測(Corner Detection)是計算機視覺系統中用來獲得影象特徵的一種方法,廣泛應用於運動檢測、影象匹配、視訊跟蹤、三維建模和目標識別等領域中。也稱為特徵點檢測。

       角點通常被定義為兩條邊的交點,更嚴格的說,角點的區域性鄰域應該具有兩個不同區域的不同方向的邊界。而實際應用中,大多數所謂的角點檢測方法檢測的是擁有特定特徵的影象點,而不僅僅是“角點”。這些特徵點在影象中有具體的座標,並具有某些數學特徵,如區域性最大或最小灰度、某些梯度特徵等。

現有的角點檢測演算法並不是都十分的健壯。很多方法都要求有大量的訓練集和冗餘資料來防止或減少錯誤特徵的出現。另外,角點檢測方法的一個很重要的評價標準是其對多幅影象中相同或相似特徵的檢測能力,並且能夠應對光照變化、影象旋轉等影象變化。

 如果某一點在任意方向的一個微小變動都會引起灰度很大的變化,那麼我們就把它稱之為角點

首先我們來看三幅圖片理解什麼是角點:

我們在圖片以某畫素點為中心,取一視窗,當視窗向各個方向移動時,其內部灰度值變化不是很明顯,則該點即處在平坦區域(如左邊圖);當其內部灰度值只在幾個固定的方向上變化較為明顯,那麼該點則處在邊緣區域(如圖中間部分);當向各個方向移動,其變化都是很明顯,則該點為角點(如圖右)


另外,關於角點的具體描述可以有幾種:

  1. ·   一階導數(即灰度的梯度)的區域性最大所對應的畫素點;
  2. ·  兩條及兩條以上邊緣的交點;
  3. ·  影象中梯度值和梯度方向的變化速率都很高的點;
  4. ·  角點處的一階導數最大,二階導數為零,指示物體邊緣變化不連續的方向。

 二、moravvec角點

           Moravec 在1981年提出Moravec角點檢測運算元[1],並將它應用於立體匹配。

          首先, 計算每個畫素點的興趣值, 即以該畫素點為中心, 取一個w*w(如:5×5)的方形視窗, 計算0度、45度、90度、135度四個方向灰度差的平方和, 取其中的最小值作為該畫素點的興趣值.E就是畫素的變化值。Moravec運算元對四個方向進行加權求和來確定變化的大小,然和設定閾值,來確定到底是邊還是角點。

                                                   

                                         圖   以3×3為例 黑色視窗為I(x,y) 紅色視窗為I(x+u,y+v)

             其中四種移位 (u,v) = (1,0), (1,1), (0,1), (-1, 1).w(x,y)為方形二值視窗,若畫素點在視窗內,則取值為1, 否則為0。

      moravec角點檢測步驟:

      (1)對於每一個畫素點,計算在E(u,v),在我們的演算法中,(u,v)的取值是((1,0), (1,1),(0,1), (-1, 1).當然,你自己可以改成(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1)8種情況

    (2)計算最小值對每個位置minValue = min{E(u,v)},其中(u,v) = (1,0),(1,1), (0,1), (-1, 1).

      (3)對每個位置minValue 進行判斷,是不是大於設定閾值,如果是大於設定閾值,接著判斷是不是區域性極大,在判斷角點的時候,必須判斷每個方向的patch的變化。

moravec角點檢測主要有兩個缺點

  • 不具有旋轉不變性
  • 對邊緣點的反應比較強烈
<span style="font-size:18px;">#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
// MoravecCorners角點檢測
cv::Mat MoravecCorners(cv::Mat srcImage, int kSize, int threshold)
{
	cv::Mat resMorMat = srcImage.clone();
	int r = kSize / 2;
	const int nRows = srcImage.rows;
	const int nCols = srcImage.cols;
	int nConut = 0;
	CvPoint *pPoint = new CvPoint[nRows*nCols];
	for (int i = r; i < srcImage.rows-r; i++)
	{
		for (int j = r; j<srcImage.cols-r; j++)
		{
			int wV1, wV2, wV3, wV4;
			wV1 = wV2 = wV3 = wV4 = 0;
			for (int k = -r; k < r; k++)
				wV1 += (srcImage.at<uchar>(i,j+k)-
				srcImage.at<uchar>(i,j+k+1))*(srcImage.at
				<uchar>(i,j+k)-srcImage.at<uchar>(i,j+k+1));
			for (int k = -r; k < r; k++)
				wV2 += (srcImage.at<uchar>(i+k,j)-
				srcImage.at<uchar>(i+k+1,j))*(srcImage.at
				<uchar>(i+k,j)-srcImage.at<uchar>(i+k+1,j));
			for (int k = -r; k < r; k++)
				wV3 += (srcImage.at<uchar>(i+k,j+k)-
				srcImage.at<uchar>(i+k+1,j+k+1))*(srcImage.at
				<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j+k+1));
			for (int k = -r; k < r; k++)
				wV4 += (srcImage.at<uchar>(i+k,j-k)-
				srcImage.at<uchar>(i+k+1,j-k-1))*(srcImage.at
				<uchar>(i+k,j-k)-srcImage.at<uchar>(i+k+1,j-k-1));
			int value = min(min(wV1,wV2), min(wV3,wV4));
			if (value > threshold)
			{
				pPoint[nConut] = cvPoint(j,i);
				nConut++;
			}
		}
	}
	for (int i = 0; i < nConut; i++)
		cv::circle(resMorMat, pPoint[i], 5, cv::Scalar(255,0,0));
    return resMorMat;
}

int main()
{
	cv::Mat srcImage = imread("lena.jpg",0);
	if (!srcImage.data)
		return -1;
	cv::Mat resMorMat =  MoravecCorners(srcImage, 5,10000);
	cv::imshow("srcImage", srcImage);
	cv::imshow("resMorMat",resMorMat);
	cv::waitKey(0);
	return 0;
}</span>

 

 三、harris角點檢測

       在harris的角點檢測中,使用的是高斯視窗,所以w(x,y)表示的是高斯視窗中的權重。此時 當u和v取兩組相互垂直的值時,E(u,v)都有較大值的點。

 

<1>計算影象I(x,y)在x和y兩個方向的梯度Ix,Iy


結果解釋:

  • 角點:最直觀的印象就是在水平、豎直兩個方向上變化均較大的點,即Ix、Iy都較大
  • 邊緣:僅在水平、或者僅在豎直方向有較大的變化量,即Ix和Iy只有其一較大
  • 平坦地區:在水平、豎直方向的變化量均較小,即Ix、Iy都較小
或者說,r1 r2是特徵值
  • r1,r2都很小,對應於影象中的平滑區域
  • r1,r2都很大,對應於影象中的角點
  • r1,r2一個很大,一個很小,對應於影象中的邊緣

      Harris角點檢測最直觀的解釋是:在任意兩個相互垂直的方向上,都有較大變化的點。

      在moravec角點檢測中,w(x,y)的取值是二元的,在視窗內部就取值為1,在視窗外部就取值為0,在harris的角點檢測中,使用的是高斯視窗,所以w(x,y)表示的是高斯視窗中的權重。此時 當u和v取兩組相互垂直的值時,E(u,v)都有較大值的。

Harris角點檢測演算法有諸多優點:

  •  旋轉不變性,橢圓轉過一定角度但是其形狀保持不變(特徵值保持不變)
  •  對於影象灰度的仿射變化具有部分的不變性,由於僅僅使用了影象的一介導數,對於影象灰度平移變化不變;對於影象灰度尺度變化不變

當然Harris也有許多不完善的地方:它對尺度很敏感,不具備幾何尺度不變性。

      cornerHarris 函式用於在OpenCV中執行Harris角點檢測運算元處理影象。和cornerMinEigenVal( )以及cornerEigenValsAndVecs( )函式類似,cornerHarris 函式對於每一個畫素(x,y)在鄰域內,計算2x2梯度的協方差矩陣,接著它計算如下式子:

 

即可以找出輸出圖中的區域性最大值,即找出了角點。

<span style="font-size:18px;">C++: void cornerHarris(InputArraysrc,OutputArray dst, int blockSize, int ksize, double k,intborderType=BORDER_DEFAULT )
第一個引數,InputArray型別的src,輸入影象,即源影象,填Mat類的物件即可,且需為單通道8位或者浮點型影象。
第二個引數,OutputArray型別的dst,函式呼叫後的運算結果存在這裡,即這個引數用於存放Harris角點檢測的輸出結果,和源圖片有一樣的尺寸和型別。
第三個引數,int型別的blockSize,表示鄰域的大小,更多的詳細資訊在cornerEigenValsAndVecs()中有講到。
第四個引數,int型別的ksize,表示Sobel()運算元的孔徑大小。
第五個引數,double型別的k,Harris引數。
第六個引數,int型別的borderType,影象畫素的邊界模式,注意它有預設值BORDER_DEFAULT。更詳細的解釋,參考borderInterpolate( )函式。</span>
<span style="font-size:18px;">#include <opencv2/opencv.hpp>  
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
using namespace cv;  
using namespace std;  
#define WINDOW_NAME1 "【程式視窗1】"        
#define WINDOW_NAME2 "【程式視窗2】"        
Mat g_srcImage, g_srcImage1,g_grayImage;  
int thresh = 30; 
int max_thresh = 175; 
void on_CornerHarris( int, void* );//回撥函式  
int main( int argc, char** argv )  
{  
    g_srcImage = imread( "1.jpg", 1 );  
     if(!g_srcImage.data ) { printf("讀取圖片錯誤,請確定目錄下是否有imread函式指定的圖片存在~! \n"); return false; }    
     imshow("原始圖",g_srcImage);  
    g_srcImage1=g_srcImage.clone( );  
    cvtColor( g_srcImage1, g_grayImage, CV_BGR2GRAY );  
    namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );  
    createTrackbar( "閾值: ", WINDOW_NAME1, &thresh, max_thresh, on_CornerHarris );  
    on_CornerHarris( 0, 0 );  
    waitKey(0);  
    return(0);  
}  
  
void on_CornerHarris( int, void* )  
{  

    Mat dstImage;
    Mat normImage;
    Mat scaledImage;
    dstImage = Mat::zeros( g_srcImage.size(), CV_32FC1 );  
    g_srcImage1=g_srcImage.clone( );  
    cornerHarris( g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT );  
    normalize( dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );  
    convertScaleAbs( normImage, scaledImage );
    for( int j = 0; j < normImage.rows ; j++ )  
    { for( int i = 0; i < normImage.cols; i++ )  
    {  
        if( (int) normImage.at<float>(j,i) > thresh+80 )  
        {  
            circle( g_srcImage1, Point( i, j ), 5,  Scalar(10,10,255), 2, 8, 0 );  
            circle( scaledImage, Point( i, j ), 5,  Scalar(0,10,255), 2, 8, 0 );  
        }  
    }  
    }  
    imshow( WINDOW_NAME1, g_srcImage1 );  
    imshow( WINDOW_NAME2, scaledImage );  
  
}  
</span>


四、知識補充

     關於矩陣知識的一點補充:好長時間沒看過線性代數的話,這一段比較難理解。可以看到M是實對稱矩陣,這裡簡單溫習一下實對稱矩陣和二次型的一些知識點吧。

1. 關於特徵值和特徵向量: 

特徵值的特徵向量的概念忘了就自己查吧,這裡只說關鍵的。對於實對稱矩陣M(設階數為n),則一定有n個實特徵值,每個特徵值對應一組特徵向量(這組向量中所有向量共線),不同特徵值對應的特徵向量間相互正交;(注意這裡說的是實對稱矩陣,不是所有的矩陣都滿足這些條件)

2. 關於對角化:

對角化是指存在一個正交矩陣Q,使得  Q’MQ 能成為一個對角陣(只有對角元素非0),其中Q’是Q的轉置(同時也是Q的逆,因為正交矩陣的轉置就是其逆)。一個矩陣對角化後得到新矩陣的行列式和矩陣的跡(對角元素之和)均與原矩陣相同。如果M是n階實對稱矩陣,則Q中的第 j 列就是第 j 個特徵值對應的一個特徵向量(不同列的特徵向量兩兩正交)。

3. 關於二次型:

對於一個n元二次多項式,f(x1,x2....xn)= ∑ ( aij*xi*xj ) ,其中 i 和 j 的求和區間均為 [1,n] ,

可將其各次的係數 aij 寫成一個n*n矩陣M,由於 aij 和 aji 的對稱等價關係,一般將 aij 和 aji 設為一樣的值,均為xi*xj 的係數的二分之一。這樣,矩陣M就是實對稱矩陣了。即二次型的矩陣預設都是實對稱矩陣

4. 關於二次型的標準化(正交變換法):

二次型的標準化是指通過構造一個n階可逆矩陣 C,使得向量 ( x1,x2...xn ) = C * (y1,y2...yn),把n維向量 x 變換成n維向量 y ,並代入f(x1,x2....xn) 後得到 g(y1,y2...yn),而後者的表示式中的二次項中不包含任何交叉二次項 yi*yj(全部都是平方項 yi^2),也即表示式g的二次型矩陣N是對角陣。用公式表示一下 f 和 g ,(下面的表示式中 x 和 y都代表向量,x' 和 y' 代表轉置)

f = x' * M * x ;

g = f = x' * M * x = (Cy)' * M * (Cy) = y'* (C'MC) * y = y' * N * y  ;

因此 C‘MC = N。正交變換法,就是直接將M對角化得到N,而N中對角線的元素就是M的特徵值。正交變換法中得到的 C 正好是一個正交矩陣,其每一列都是兩兩正交的單位向量,因此 C 的作用僅僅是將座標軸旋轉(不會有放縮)。


影象識別演算法交流 QQ群:145076161,歡迎影象識別與影象演算法,共同學習與交流