Comment puis-je calculer la courbure d’un contour extrait par opencv?

J’ai effectivement utilisé la méthode findcontours() pour extraire le contour de l’image, mais je ne sais pas comment calculer la courbure à partir d’un ensemble de points de contour. Quelqu’un peut m’aider? Merci beaucoup!

Pour moi, la courbure est:

t est la position à l’intérieur du contour et x(t) resp. y(t) retourne le x lié resp. y valeur. Voir ici

Donc, selon ma définition de la courbure, on peut l’implémenter de cette façon:

 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; } 

Cela fonctionne également sur les listes de points non fermées. Pour les contours fermés, vous souhaiterez peut-être modifier le comportement des limites (pour les premières itérations).

METTRE À JOUR:

Explication pour les dérivés:

Une dérivée pour une fonction continue à 1 dimension f(t) est:

Mais nous sums dans un espace discret et avons deux fonctions discrètes f_x(t) et f_y(t) où le plus petit pas pour t est un.

La seconde dérivée est la dérivée de la première dérivée:

En utilisant l’approximation de la première dérivée, il en résulte:

Il existe d’autres approximations pour les dérivées, si vous la recherchez sur Google, vous en trouverez beaucoup.

Bien que la théorie derrière la réponse de Gombat soit correcte, il existe des erreurs dans le code ainsi que dans les formules (le dénominateur t+nx devrait être t+nt ). J’ai apporté plusieurs modifications:

  • utiliser des dérivées symésortingques pour obtenir des emplacements plus précis des maxima de courbure
  • permet d’utiliser une taille de pas pour le calcul dérivé (peut être utilisé pour réduire le bruit des contours bruyants)
  • fonctionne avec des contours fermés

Corrections: * retourne l’infini comme courbure si le dénominateur est 0 (pas 0) * calcul du carré ajouté dans le dénominateur * vérification correcte pour 0 diviseur

 std::vector getCurvature(std::vector 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::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::infinity(); } vecCurvature[i] = curvature2D; } return vecCurvature; }