PCL—低層次視覺—關鍵點檢測(Harris)


  除去NARF這種和特征檢測聯系比較緊密的方法外,一般來說特征檢測都會對曲率變化比較劇烈的點更敏感。Harris算法是圖像檢測識別算法中非常重要的一個算法,其對物體姿態變化魯棒性好,對旋轉不敏感,可以很好的檢測出物體的角點。甚至對於標定算法而言,HARRIS角點檢測是使之能成功進行的基礎。

  HARRIS算法的思想還是很有意思的。很聰明也很trick.

1.Harris 算法 

  其思想及數學推導大致如下:

  

  1.在圖像中取一個窗 w (矩形窗,高斯窗,XX窗,各種窗,某師姐要改標定算法不就可以從選Harris的窗開始做起么。。。。。)

  2.獲得在該窗下的灰度  I

  3.移動該窗,則灰度會發生變化,平坦區域灰度變化不大,邊緣區域沿邊緣方向灰度變化劇烈,角點處各個方向灰度變化均劇烈

  4.依據3中條件選出角點

 

  當然啦,如果Harris算子的實現也和它的思想這么平淡那我就不表揚他聰明了,Harris算子的具體實現方法,利用的是圖像偏微分方程的思想。

  先給出抽象數學表達式(不要問我為什么這么淡,我也不知道):

 

  其中 w 代表窗函數,某個x,y為圖像坐標,u,v是一個移動向量(既反應移動方向,也反應移動大小)。

 

  Ix表示圖像沿x方向的差分,Iy表示圖像沿y方向的差分。圖像差分算子有什么Sober~PXX~總之很多就對了,一階差分還是很好求的。

  

  顯然,E(u,v)可以用另外一種形式來表示了。最終可以表達為協方差矩陣的形式。

  OK,在這里我們有了數學中最優雅的表達——Matrix,especially symmetric Matrix. Nothing is better than that.

  

2.矩陣的方向性

  

  顯然,E(u,v)的值和u,v有關。。。很有關。。

  1.可以取一組u,v,讓E(u,v)的值最小。

  2.還可以取一組u,v,讓E(u,v)的值最大。

  

  這些u,v怎么取,顯然就和矩陣M的方向有關了。OK,讓我們換一個思路來看這個矩陣。

  平面內的一個矩陣乘以一個向量v,大概簡單的寫成   Mv

  它會使得這個向量發生一個作用:旋轉,拉伸,平移.....總之,這種作用叫做  線性變換

  矩陣的左邊好像也是一個向量,只不過是橫着寫的([u v]),換而言之,那就是 vT(v的轉置)。

  vT(Mv)......這是啥?

  意思好像是。。。。v先旋轉+拉伸一下,然后再在它自己身上投影,最終的 E(u,v)本質上來說,就是這個投影的長度。。。嗯,對,投影的長度

  好了。我們現在明確了 E(u,v) 的數學幾何意義,再回過頭來想想,要怎樣才能讓這個投影的長度達到最大或者最小呢?

  顯然,答案就是矩陣的特征值特征向量,當[u v]T 取特征向量方向的時候,矩陣M只有拉伸作用,而沒有旋轉作用,這時的投影長度是最長的(如果反向投則是負的最長)。

  

  到此為止,我們已經知道了 E(u,v)的最大和最小值了(笨辦法是求出特征向量方向再帶進去,聰明的方法是直接看矩陣特征值,特征值就是放大倍數)。並且,分析可以知道,特征值越大,那么說明 E(u,v)越大。

  1.兩個特征值都很大==========>角點(兩個響應方向)

  2.一個特征值很大,一個很小=====>邊緣(只有一個響應方向)

  3.兩個特征值都小============>平原地區(響應都很微弱)

 

  基於上述特征,有很多人設計了角點的快速判據。

  有 det(M) - trace(M)^2

  有 det(M)/trace(M)

  .....等等很多,但是這不重要,思想都是一樣的。(某師姐這里又有一個標定算法的創新點哦。。。。我會告訴你換換判據又是個新思路?)

  

3. 3DHarris 

  在2DHarris里,我們使用了 圖像梯度構成的 協方差矩陣。 圖像梯度。。。嗯。。。。每個像素點都有一個梯度,在一階信息量的情況下描述了兩個相鄰像素的關系。顯然這個思想可以輕易的移植到點雲上來。

  OOPS,糟糕,點雲木有灰度的概念啊,一般的點雲也木有強度的概念啊。。。這可如何是好??????

  別緊張,pcl 說這樣能行,那就肯定能行咯,先定性的分析一下Harris3D的理念。

  想象一下,如果在 點雲中存在一點p

  1、在p上建立一個局部坐標系:z方向是法線方向,x,y方向和z垂直。

  2、在p上建立一個小正方體,不要太大,大概像材料力學分析應力那種就行

  3、假設點雲的密度是相同的,點雲是一層蒙皮,不是實心的。

    a、如果小正方體沿z方向移動,那小正方體里的點雲數量應該不變

    b、如果小正方體位於邊緣上,則沿邊緣移動,點雲數量幾乎不變,沿垂直邊緣方向移動,點雲數量改變

    c、如果小正方體位於角點上,則有兩個方向都會大幅改變點雲數量

  OK,我們已經有了Harris3D的基本准則,接下來要思考的是怎樣優雅的解決這個問題

  

  兩個和z相互垂直的方向。。。。嗯。。。。perpendicular。。。。

  如果由法向量x,y,z構成協方差矩陣,那么它應該是一個對稱矩陣。而且特征向量有一個方向是法線方向,另外兩個方向和法線垂直。

  那么直接用協方差矩陣替換掉圖像里的M矩陣,就得到了點雲的Harris算法。

  其中,半徑r可以用來控制角點的規模

  r小,則對應的角點越尖銳(對噪聲更敏感)
  r大,則可能在平緩的區域也檢測出角點

  r怎么取? 我也不知道。。。。。試吧。。。。。

 

 4.PCL對Harris算法的實現

  根據以上分析,在PCL的API文檔的幫助下,我嘗試了一下 Harris3D 算法。感謝山大的畢同學提供的點雲,該點雲是場景點雲而不是一般的物體點雲。總體感覺是慢,因為針對每個點雲,需要計算它的法線,算完之后又要針對每個點進行協方差矩陣的計算,總而言之,整個過程還是非常耗時的。並且說實話。。。算法的效果一般般。

  

#include <iostream>
#include <pcl\io\pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/io.h>
#include <pcl/keypoints/harris_keypoint3D.h>
#include <cstdlib>
#include <vector>
using namespace std;



int
main()
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile ("F:\\PCL\\PCD\\both.pcd", *cloud);
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer);
    viewer->addPointCloud(cloud,"all_cloud");
        //注意Harris的輸出點雲必須是有強度(I)信息的,因為評估值保存在I分量里
    pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_out (new pcl::PointCloud<pcl::PointXYZI>);
    pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal> harris;
    harris.setInputCloud(cloud);
    cout<<"input successful"<<endl;
    harris.setNonMaxSupression(true);
    harris.setRadius(0.04f);
    harris.setThreshold(0.02f);
    cout<<"parameter set successful"<<endl;
        //新建的點雲必須初始化,清零,否則指針會越界
    cloud_out->height=1;
    cloud_out->width =100;
    cloud_out->resize(cloud_out->height*cloud->width);    
        cloud_out->clear();
    harris.compute(*cloud_out);
    int size = cloud_out->size();

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_harris (new pcl::PointCloud<pcl::PointXYZ>);
    cloud_harris->height=1;
    cloud_harris->width =100;
    cloud_harris->resize(cloud_out->height*cloud->width);
    cloud_harris->clear();

    pcl::PointXYZ point;
        //可視化結果不支持XYZI格式點雲,所有又要導回XYZ格式。。。。
    for (int i = 0;i<size;i++)
    {    
        point.x = cloud_out->at(i).x;
        point.y = cloud_out->at(i).y;
        point.z = cloud_out->at(i).z;
        cloud_harris->push_back(point);
    }



    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> harris_color_handler (cloud_harris, 0, 255, 0);
    viewer->addPointCloud(cloud_harris,harris_color_handler,"harris");
    viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "harris");




    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);

    }
    
        system("pause");
}    

  由於我選擇的搜索半徑比較大,所以找到的角點都不是太"角”,關於參數設置大家可以多多探索,但我認為,特征點檢測算法實在太慢,對實時機器人系統來說是遠遠達不到要求的。這種先算法線,再算協方差的形式真心上不起。。。。實際上這種基於領域法線的特征點檢測算法有點類似基於 CRF的語義識別算法,都只使用了相鄰信息而忽略了全局信息。也可能相鄰信息包含的相關性比較大,是通往高層次感知的唯一路徑吧,誰又知道呢?

  任重而道遠。。。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM