光條中心線提取-Steger算法(基於Hessian矩陣)

採用結構光進行掃描檢測時,需要提取激光條紋的中心線,本文采用經典的Steger算法提取光條中心。

Steger算法原理

Steger算法基於Hessian矩陣,能夠實現光條中心亞像素精度定位:首先通過Hessian矩陣能夠得到光條的法線方向,然後在法線方向利用泰勒展開得到亞像素位置。
對於圖像中激光條紋上的任意一點(x,y) ,Hessian矩陣可以表示爲:

H(x,y)=[rxxrxyrxyryy]

其中rxx 表示圖像沿x的二階偏導數,其他參數類似。需要注意的是在求Hessian矩陣之前需要對圖像進行高斯濾波,高斯濾波時,根據文獻[1]中,設置高斯方差σ<w3 ,其中w 爲光條寬度。Hessian矩陣最大特徵值對應的特徵向量對應於光條的法線方向,用(nx,ny) 表示,以點(x0,y0) 爲基準點,則光條中心的亞像素座標爲:
(px,py)=(x0+tnxy0+tny)
公式中
t=nxrx+nyryn2xrxx+2nxnyrxy+n2yryy
如果(tnx,tny)[0.5,0.5]×[0.5,0.5] ,即一階導數爲零的點位於當前像素內,且(nx,ny) 方向的二階導數大於指定的閾值,則該點(x0,y0) 爲光條的中心點,(px,py) 則爲亞像素座標。

示例代碼

根據Steger算法的原理,藉助opencv的Mat數據結構,實現Steger算法如下:

void StegerLine()
{ 
    Mat img0 = imread("image_0.png", 1);
    Mat img;
    cvtColor(img0, img0, CV_BGR2GRAY);
    img = img0.clone();

    //高斯濾波
    img.convertTo(img, CV_32FC1);
    GaussianBlur(img, img, Size(0, 0), 6, 6);

    //一階偏導數
    Mat m1, m2;
    m1 = (Mat_<float>(1, 2) << 1, -1);  //x偏導
    m2 = (Mat_<float>(2, 1) << 1, -1);  //y偏導

    Mat dx, dy;
    filter2D(img, dx, CV_32FC1, m1);
    filter2D(img, dy, CV_32FC1, m2);

    //二階偏導數
    Mat m3, m4, m5;
    m3 = (Mat_<float>(1, 3) << 1, -2, 1);   //二階x偏導
    m4 = (Mat_<float>(3, 1) << 1, -2, 1);   //二階y偏導
    m5 = (Mat_<float>(2, 2) << 1, -1, -1, 1);   //二階xy偏導

    Mat dxx, dyy, dxy;
    filter2D(img, dxx, CV_32FC1, m3);
    filter2D(img, dyy, CV_32FC1, m4);
    filter2D(img, dxy, CV_32FC1, m5);

    //hessian矩陣
    double maxD = -1;
    int imgcol = img.cols;
    int imgrow = img.rows;
    vector<double> Pt;
    for (int i=0;i<imgcol;i++)
    {
        for (int j=0;j<imgrow;j++)
        {
            if (img0.at<uchar>(j,i)>200)
            {
                Mat hessian(2, 2, CV_32FC1);
                hessian.at<float>(0, 0) = dxx.at<float>(j, i);
                hessian.at<float>(0, 1) = dxy.at<float>(j, i);
                hessian.at<float>(1, 0) = dxy.at<float>(j, i);
                hessian.at<float>(1, 1) = dyy.at<float>(j, i);

                Mat eValue;
                Mat eVectors;
                eigen(hessian, eValue, eVectors);

                double nx, ny;
                double fmaxD = 0;
                if (fabs(eValue.at<float>(0,0))>= fabs(eValue.at<float>(1,0)))  //求特徵值最大時對應的特徵向量
                {
                    nx = eVectors.at<float>(0, 0);
                    ny = eVectors.at<float>(0, 1);
                    fmaxD = eValue.at<float>(0, 0);
                }
                else
                {
                    nx = eVectors.at<float>(1, 0);
                    ny = eVectors.at<float>(1, 1);
                    fmaxD = eValue.at<float>(1, 0);
                }

                double t = -(nx*dx.at<float>(j, i) + ny*dy.at<float>(j, i)) / (nx*nx*dxx.at<float>(j,i)+2*nx*ny*dxy.at<float>(j,i)+ny*ny*dyy.at<float>(j,i));

                if (fabs(t*nx)<=0.5 && fabs(t*ny)<=0.5)
                {
                    Pt.push_back(i);
                    Pt.push_back(j);
                }
            }
        }
    }

    for (int k = 0;k<Pt.size()/2;k++)
    {
        Point rpt;
        rpt.x = Pt[2 * k + 0];
        rpt.y = Pt[2 * k + 1];
        circle(img0, rpt, 1, Scalar(0, 0, 255));
    }

    imshow("result", img0);
    waitKey(0);
}

示例結果

這裏寫圖片描述

  1. Steger C. An unbiased detector of curvilinear structures. IEEE Trans Pattern Anal Mach Intell[J]. IEEE Transactions on Pattern Analysis & Machine Intelligence, 1998, 20(2):113-125.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章