2015-09-17 479 views
7

我確實使用了findcontours()方法從圖像中提取輪廓,但我不知道如何從一組輪廓點計算曲率。有人能幫助我嗎?非常感謝你!如何通過opencv計算提取輪廓的曲率?

+0

如果您向我們提供您已經嘗試過的事項清單並提供更具體的問題,這將有極大的幫助。 – YePhIcK

回答

4

對於我曲率是:

其中t是輪廓和x(t) RESP內部的位置。 y(t)返回相關的x或分別。值爲y。見here

所以,根據我的曲率的定義,一個可以實現這樣說:

std::vector<float> vecCurvature(vecContourPoints.size()); 

cv::Point2f posOld, posOlder; 
cv::Point2f f1stDerivative, f2ndDerivative; 
for (size_t i = 0; i < vecContourPoints.size(); i++) 
{ 
    const cv::Point2f& pos = vecContourPoints[i]; 

    if (i == 0){ posOld = posOlder = pos; } 

    f1stDerivative.x = pos.x -  posOld.x; 
    f1stDerivative.y = pos.y -  posOld.y; 
    f2ndDerivative.x = - pos.x + 2.0f * posOld.x - posOlder.x; 
    f2ndDerivative.y = - pos.y + 2.0f * posOld.y - posOlder.y; 

    float curvature2D = 0.0f; 
    if (std::abs(f2ndDerivative.x) > 10e-4 && std::abs(f2ndDerivative.y) > 10e-4) 
    { 
     curvature2D = sqrt(std::abs( 
      pow(f2ndDerivative.y*f1stDerivative.x - f2ndDerivative.x*f1stDerivative.y, 2.0f)/
      pow(f2ndDerivative.x + f2ndDerivative.y, 3.0))); 
    } 

    vecCurvature[i] = curvature2D; 

    posOlder = posOld; 
    posOld = pos; 
} 

它適用於非封閉pointlists爲好。對於封閉輪廓,您可能想要更改邊界行爲(對於第一次迭代)。

UPDATE:

解釋爲衍生物:

一種用於連續1個維函數f(t)衍生物是:

但是,我們是在一個離散的空間,並且具有兩個離散函數f_x(t)f_y(t)其中最小的步驟爲t就是其中之一。

二階導數是一階導數的導數:使用一階導數的近似值

,它產生於:

如果y有衍生物的其他近似值ou谷歌它,你會發現很多。

+0

感謝您的評論。但我不明白爲什麼f1stDerivative.x和f2ndDerivative.x可以計算爲您在代碼中顯示的表單? – kookoo121

+0

這有幾個選項。我爲答案添加了一個解釋。 – Gombat

+0

非常感謝! – kookoo121

5

雖然Gombat的答案背後的理論是正確的,但在代碼和公式中有一些錯誤(分母t+n-x應該是t+n-t)。我已經提出了一些改變:

  • 使用對稱衍生物獲得曲率最大值的更精確的位置
  • 允許使用的步長爲導數計算(可以用來減少從嘈雜輪廓噪聲)
  • 作品與閉合輪廓

修正: *返回無窮大的曲率,如果分母爲0(不爲0) *加入平方計算中的分母 *正確爲0除數檢查

std::vector<double> getCurvature(std::vector<cv::Point> const& vecContourPoints, int step) 
{ 
    std::vector<double> vecCurvature(vecContourPoints.size()); 

    if (vecContourPoints.size() < step) 
    return vecCurvature; 

    auto frontToBack = vecContourPoints.front() - vecContourPoints.back(); 
    std::cout << CONTENT_OF(frontToBack) << std::endl; 
    bool isClosed = ((int)std::max(std::abs(frontToBack.x), std::abs(frontToBack.y))) <= 1; 

    cv::Point2f pplus, pminus; 
    cv::Point2f f1stDerivative, f2ndDerivative; 
    for (int i = 0; i < vecContourPoints.size(); i++) 
    { 
     const cv::Point2f& pos = vecContourPoints[i]; 

     int maxStep = step; 
     if (!isClosed) 
     { 
      maxStep = std::min(std::min(step, i), (int)vecContourPoints.size()-1-i); 
      if (maxStep == 0) 
      { 
       vecCurvature[i] = std::numeric_limits<double>::infinity(); 
       continue; 
      } 
     } 


     int iminus = i-maxStep; 
     int iplus = i+maxStep; 
     pminus = vecContourPoints[iminus < 0 ? iminus + vecContourPoints.size() : iminus]; 
     pplus = vecContourPoints[iplus > vecContourPoints.size() ? iplus - vecContourPoints.size() : iplus]; 


     f1stDerivative.x = (pplus.x -  pminus.x)/(iplus-iminus); 
     f1stDerivative.y = (pplus.y -  pminus.y)/(iplus-iminus); 
     f2ndDerivative.x = (pplus.x - 2*pos.x + pminus.x)/((iplus-iminus)/2*(iplus-iminus)/2); 
     f2ndDerivative.y = (pplus.y - 2*pos.y + pminus.y)/((iplus-iminus)/2*(iplus-iminus)/2); 

     double curvature2D; 
     double divisor = f1stDerivative.x*f1stDerivative.x + f1stDerivative.y*f1stDerivative.y; 
     if (std::abs(divisor) > 10e-8) 
     { 
      curvature2D = std::abs(f2ndDerivative.y*f1stDerivative.x - f2ndDerivative.x*f1stDerivative.y)/
       pow(divisor, 3.0/2.0) ; 
     } 
     else 
     { 
      curvature2D = std::numeric_limits<double>::infinity(); 
     } 

     vecCurvature[i] = curvature2D; 


    } 
    return vecCurvature; 
}