How to calculate opencv selected loop curvature?

I used the findcontours() method to extract the contour from the image, but I do not know how to calculate the curvature from the set of contour points. Can someone help me? Thank you very much!

+7
c ++ opencv
source share
2 answers

For me, the curvature:

gif.latex?|K|&space;=&space;%5Csqrt%7B&space;%5Cfrac%7B&space;%5Cleft(%5Cfrac%7Bd%5E2y(t)%7D%7Bdt%5E2%7D%5Cfrac%7Bdx(t))%7D%7Bdt%7D-%5Cfrac%7Bd%5E2x(t)%7D%7Bdt%5E2%7D%5Cfrac%7Bdy(t)%7D%7Bdt%7D&space;%5Cright&space;)%5E2&space;%7D%7B&space;%5Cleft(&space;%5Cfrac%7Bd%5E2x(t)%7D%7Bdt%5E2%7D+%5Cfrac%7Bd%5E2y(t)%7D%7Bdt%5E2%7D&space;%5Cright&space;)%5E%7B3%7D&space;%7D&space;%7D

where t is the position inside the contour and x(t) respectively. y(t) return the associated x resp. y . See here .

So, according to my definition of curvature, this can be implemented like this:

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

He works on unclosed lists. For closed loops, you can change the behavior of the border (for the first iterations).

UPDATE:

Explanation for derivatives:

The derivative for the continuous one-dimensional function f(t) :

gif.latex?f%27(t)=%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf(t&plus;n)-f(t))%7D%7Bt&plus;n-x%7D%7D&space;=&space;%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf(t&plus;n)-f(t))%7D%7Bn%7D%7D

But we are in a discrete space and have two discrete functions f_x(t) and f_y(t) , where the smallest step for t is one.

gif.latex?f_x%27(t)=%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf_x(t&plus;n)-f_x(t))%7D%7Bt&plus;n-x%7D%7D&space;=&space;%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf_x(t&plus;n)-f_x(t))%7D%7Bn%7D%7D&space;%5Capprox&space;%5Cfrac%7Bf_x(t&plus;1)-f_x(t))%7D%7B1%7D

The second derivative is derived from the first derivative:

gif.latex?f_x%27%27(t)=%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf_x%27(t&plus;n)-f_x%27(t))%7D%7Bt&plus;n-x%7D%7D&space;=&space;%5Clim%5Climits_%7Bn&space;%5Crightarrow&space;0%7D%7B%5Cfrac%7Bf_x%27(t&plus;n)-f_x%27(t))%7D%7Bn%7D%7D&space;%5Capprox&space;%5Cfrac%7Bf_x%27(t&plus;1)-f_x%27(t))%7D%7B1%7D

Using the approximation of the first derivative, it gives:

gif.latex?f_x%27%27(t)=(f_x(t&plus;2)-f_x(t&plus;1))&space;-&space;(f_x(t&plus;1)-f_x(t))&space;=&space;f_x(t&plus;2)&space;-&space;2f_x(t&plus;1)&space;&plus;&space;f_x(t)

There are other approximations for derivatives, if you find them on Google, you will find many.

+4
source share

While Gombatโ€™s answer theory is correct, there are errors in the code as well as in formulas (the denominator t+nx must be t+nt ). I made a few changes:

  • use symmetric derivatives to obtain more precise places of curvature maxima
  • allow you to use the step size to calculate derivatives (can be used to reduce noise from noisy circuits)
  • works with closed circuits

Corrections: * return infinity as curvature if the denominator is 0 (not 0) * a square calculation in the denominator is added * the correct check for the 0 divisor

 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; } 
+5
source share

All Articles