2015-09-17 2 views
7

Я использовал метод findcontours() для извлечения контура из изображения, но я понятия не имею, как вычислить кривизну из набора точек контура. Может кто-нибудь мне помочь? Большое спасибо!Как вычислить кривизну выделенного контура opencv?

+0

Это очень поможет, если вы предоставите нам список вещей, которые вы уже пробовали, и с более конкретным вопросом. – YePhIcK

ответ

4

Для меня кривизна:

t где находится положение внутри контура и x(t) соответственно. 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, а также. Для закрытых контуров вы можете изменить поведение границы (для первых итераций).

ОБНОВЛЕНИЕ:

Объяснение для производных:

Производное для непрерывного 1 одномерной функции f(t) является:

Но мы в дискретном пространстве и имеют две дискретные функции f_x(t) и f_y(t), где наименьший шаг для t - один.

Вторая производная является производной от первой производной:

Используя приближение первой производной, он уступает:

Существуют другие приближения для производных, если y ou google, вы найдете много.

+0

Спасибо за ваш комментарий. Но я не понимаю, почему f1stDerivative.x и f2ndDerivative.x могут вычислять как формулу, которую вы показываете в коде? – kookoo121

+0

Существует несколько вариантов этого. Я добавляю объяснение в ответ. – Gombat

+0

Спасибо большое !!! – kookoo121

5

Хотя теория ответа Гомбата верна, в коде есть и ошибки, а также в формулах (знаменатель 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; 
} 
Смежные вопросы