如何通过opencv计算提取轮廓的曲率?

时间:2015-09-17 11:59:29

标签: c++ opencv

我确实使用findcontours()方法从图像中提取轮廓,但我不知道如何从一组轮廓点计算曲率。有人能帮助我吗?非常感谢你!

2 个答案:

答案 0 :(得分:5)

虽然Gombat的答案背后的理论是正确的,但代码和公式中都存在一些错误(分母t+n-t应该是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; } )。我做了一些改变:

  • 使用对称导数来获得更精确的曲率最大位置
  • 允许使用步长进行微分计算(可用于减少噪声等值线的噪声)
  • 使用闭合轮廓

修正: *如果分母为0(不为0),则返回无穷大作为曲率 *在分母中增加了平方计算 *正确检查0除数

importrange()

答案 1 :(得分:4)

对我来说曲率是:

其中t是轮廓内的位置,x(t)表示。 y(t)返回相关的x resp。 y值。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; } 请参阅here

所以,根据我对曲率的定义,可以用这种方式实现它:

f(t)

它也适用于非封闭的点列表。对于闭合轮廓,您可能希望更改边界行为(对于第一次迭代)。

<强>更新

衍生物的解释:

连续1维函数f_x(t)的导数是:

但我们在一个离散的空间中有两个离散函数f_y(t)t,其中resources的最小步长为1。

二阶导数是一阶导数的导数:

使用一阶导数的近似值,得到:

衍生品还有其他近似值,如果你谷歌它,你会发现很多。