查找“fitLine”的轮廓在OpenCV [英] Finding the "fitLine " of contours in OpenCV

查看:749
本文介绍了查找“fitLine”的轮廓在OpenCV的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个在流中找到轮廓的程序,例如:





我想找到一组可以描述这个轮廓的点集合,如红线:





黄色部分是轮廓的时刻,



我试图使用 fitLine 函数的opencv但结果是废话,任何Idea如何我可以得到一个轮廓的中间线,这应该代表我的轮廓的关键方面。顺便说一下* 我不是要求代码! * 只是一个提示,我该怎么办?



预先感谢任何帮助

解决方案

具有距离变换和脊检测:

  cv :: Mat input = cv :: imread(fitLine.jpg); 
cv :: Mat gray;
cv :: cvtColor(input,gray,CV_BGR2GRAY);

cv :: Mat mask = gray> 100;
cv :: imshow(mask,mask);

cv :: Mat dt;
cv :: distanceTransform(mask,dt,CV_DIST_L1,CV_DIST_MASK_PRECISE);

cv :: imshow(dt,dt / 15.0f);
cv :: imwrite(fitLineOut.png,255 * dt / 15.0f);


//关心:这部分对于对角线不工作,脊检测会更好!
cv :: Mat lines = cv :: Mat :: zeros(input.rows,input.cols,CV_8UC1);
//只取每行的maxDist
for(unsigned int y = 0; y< dt.rows; ++ y)
{
float largestDist = 0;
cv :: Point2i largestDistLoc(0,0);
for(unsigned int x = 0; x< dt.cols; ++ x)
{
cv :: Point2i current(x,y);
if(dt.at< float>(current)> largestDist)
{
largestDist = dt.at< float>(current);
largestDistLoc = current;

}
}
lines.at< unsigned char>(largestDistLoc)= 255;
}

//和每行的maxDist
for(unsigned int x = 0; x {
float largestDist = 0;
cv :: Point2i largestDistLoc(0,0);
for(unsigned int y = 0; y< dt.rows; ++ y)
{
cv :: Point2i current(x,y);
if(dt.at< float>(current)> largestDist)
{
largestDist = dt.at< float>(current);
largestDistLoc = current;

}
}
lines.at< unsigned char>(largestDistLoc)= 255;
}

cv :: imshow(max,lines);


cv :: waitKey(-1);

这个想法是计算距离变换并找到轮廓内的脊。



这是距离变换后的图像的样子:

那么我使用一个非常简单的方法:find find>>
你可以看到在行的中间有一个局部隆起最大值。

每行/列中的最大距离。这是非常马虎,应该更改为一个真正的山脊检测或稀疏方法!!!!





编辑:附加说明:



这个想法是找到位于轮廓中间的所有点。在数学/图形中,对象的某种中间中的中间轴,它的定义是所有点与至少两个轮廓点同时具有相同的最小距离。



接近中轴的方法是计算距离变换。距离变换是矩阵,其为每个像素保持到下一个物点的距离(例如对象的轮廓)(参见 http://en.wikipedia.org/wiki/Distance_transform )。这是第一个图像。在这里你可以看到,线中间的点比较靠近边界的点有点亮,这意味着沿线的最亮点可以解释为中间轴(近似),因为如果你移动远离它(正交于线方向)的距离变得越来越小,所以峰值是到两边界的距离接近相等的点。



这样if你可以在距离变换中找到那些脊,你就完成了。
脊检测通常由Harris运算符完成(请参见 http://en.wikipedia.org/ wiki / Ridge_detection )。



在我发布的快速和脏的版本中,我尝试通过只接受每个线和每行。这对于大多数水平和垂直脊,确定,但对于对角线将失败。所以也许你真的想用真实 脊检测来交换 for循环 / p>

I'm a program that find contours in a stream, for example :

I want to find "set of points " that can describe this contours say like the red line :

the yellow part is the the moments of the contours ,

I tried to use fitLine function of opencv but the result was nonsense, any Idea how can I get the middle line of a contours, that should represent the key aspect of my Contours . by the way *I'm not asking for codes ! * just a hint how can I do that ?

thanks in advance for any help

解决方案

maybe try this approach with a distance transform and ridge detection:

cv::Mat input = cv::imread("fitLine.jpg");
cv::Mat gray;
cv::cvtColor(input,gray,CV_BGR2GRAY);

cv::Mat mask = gray>100;
cv::imshow("mask",mask);

cv::Mat dt;
cv::distanceTransform(mask,dt,CV_DIST_L1,CV_DIST_MASK_PRECISE);

cv::imshow("dt", dt/15.0f);
cv::imwrite("fitLineOut.png",255*dt/15.0f);


//care: this part doesn't work for diagonal lines, a ridge detection would be better!!
cv::Mat lines = cv::Mat::zeros(input.rows, input.cols, CV_8UC1);
//only take the maxDist of each row
for(unsigned int y=0; y<dt.rows; ++y)
{
    float biggestDist = 0;
    cv::Point2i biggestDistLoc(0,0);
    for(unsigned int x=0; x<dt.cols; ++x)
    {
        cv::Point2i current(x,y);
        if(dt.at<float>(current) > biggestDist)
        {
            biggestDist = dt.at<float>(current) ;
            biggestDistLoc = current;

        }
    }
    lines.at<unsigned char>(biggestDistLoc) = 255;
}

//and the maxDist of each row
for(unsigned int x=0; x<dt.cols; ++x)
{
    float biggestDist = 0;
    cv::Point2i biggestDistLoc(0,0);
    for(unsigned int y=0; y<dt.rows; ++y)
    {
        cv::Point2i current(x,y);
        if(dt.at<float>(current) > biggestDist)
        {
            biggestDist = dt.at<float>(current) ;
            biggestDistLoc = current;

        }
    }
    lines.at<unsigned char>(biggestDistLoc) = 255;
}

cv::imshow("max", lines);


cv::waitKey(-1);

the idea is to compute the distance transform and find the ridges within the contour.

this is how the distance transformed image looks like: you can see that there is a local ridge maximum in the middle of the lines.

then I use a very simple method: just find the maximum distance in each row/column. That is very sloppy and should be changed for a real ridge detection or thinning method!!!!

edit: additional description:

The idea is to find all points that are in the "middle" of the contour. In mathematics/graphics, the medial axis in some kind of "middle" of an object and it's definition is to be all points that have the same minimum distance to at least two contour points at the same time.

A way to approximate the medial axis is to compute the distance transform. The distance transform is a matrix that holds for each pixel the distance to the next object point (for example a contour of an object)(see http://en.wikipedia.org/wiki/Distance_transform too). That's the first image. There you can see that the points in the middle of the lines are a little bit brighter than the points closer to the border, which means that the brightest points along the lines can be interpreted as the medial axis (approximation), since if you move away from it (orthogonal to the line direction) the distances become smaller, so the peak is the point where the distance to both borders in close to equality.

That way if you can find those "ridges" in the distance transform, you're done. Ridge detection is normally done by a Harris Operator (see http://en.wikipedia.org/wiki/Ridge_detection ).

In the fast and dirty version that I've posted, I try to detect the ridge by accepting only the maximum value in each line and in each row. That's ok for most horizontal and vertical ridges, but will fail for diagonal ones. So maybe you really want to exchange the for loops with a real ridge detection.

这篇关于查找“fitLine”的轮廓在OpenCV的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆