使用 OpenCV 和 Python 检测图像中的弧 [英] Detecting Arc in an image using OpenCV and Python

查看:109
本文介绍了使用 OpenCV 和 Python 检测图像中的弧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 opencv 和 Python 检测图像中的弧线.

I want to detect a arc in an image using opencv and Python.

我想要的是检测图像的绿色突出显示部分.这种形状是类似弧形的.在 SobelX 图像边界框上应用阈值后,这些弧线就会出现.我不想要这些弧上的边界框.有没有办法从顶部排除这些弧.

I want is to detect the green highlighted part of the image. This shape is of like arc type. After applying thresholding on SobelX image bounding box are coming on these arcs. I don't want bounding box on these arcs. Is there anyway to exclude these arc from top.

推荐答案

试试这个代码:它会检测所有的圆、曲线和弧:

Try this code : It will detect all the circle, curve and arc :

    int main()
{
//RANSAC

//load edge image
cv::Mat color = cv::imread("../circleDetectionEdges.png");

// convert to grayscale
cv::Mat gray;
cv::cvtColor(color, gray, CV_RGB2GRAY);

// get binary image
cv::Mat mask = gray > 0;
//erode the edges to obtain sharp/thin edges (undo the blur?)
cv::erode(mask, mask, cv::Mat());

std::vector<cv::Point2f> edgePositions;
edgePositions = getPointPositions(mask);

// create distance transform to efficiently evaluate distance to nearest edge
cv::Mat dt;
cv::distanceTransform(255-mask, dt,CV_DIST_L1, 3);

//TODO: maybe seed random variable for real random numbers.

unsigned int nIterations = 0;

char quitKey = 'q';
std::cout << "press " << quitKey << " to stop" << std::endl;
while(cv::waitKey(-1) != quitKey)
{
    //RANSAC: randomly choose 3 point and create a circle:
    //TODO: choose randomly but more intelligent, 
    //so that it is more likely to choose three points of a circle. 
    //For example if there are many small circles, it is unlikely to randomly choose 3 points of the same circle.
    unsigned int idx1 = rand()%edgePositions.size();
    unsigned int idx2 = rand()%edgePositions.size();
    unsigned int idx3 = rand()%edgePositions.size();

    // we need 3 different samples:
    if(idx1 == idx2) continue;
    if(idx1 == idx3) continue;
    if(idx3 == idx2) continue;

    // create circle from 3 points:
    cv::Point2f center; float radius;
    getCircle(edgePositions[idx1],edgePositions[idx2],edgePositions[idx3],center,radius);

    float minCirclePercentage = 0.4f;

    // inlier set unused at the moment but could be used to approximate a (more robust) circle from alle inlier
    std::vector<cv::Point2f> inlierSet;

    //verify or falsify the circle by inlier counting:
    float cPerc = verifyCircle(dt,center,radius, inlierSet);

    if(cPerc >= minCirclePercentage)
    {
        std::cout << "accepted circle with " << cPerc*100.0f << " % inlier" << std::endl;
        // first step would be to approximate the circle iteratively from ALL INLIER to obtain a better circle center
        // but that's a TODO

        std::cout << "circle: " << "center: " << center << " radius: " << radius << std::endl;
        cv::circle(color, center,radius, cv::Scalar(255,255,0),1);

        // accept circle => remove it from the edge list
        cv::circle(mask,center,radius,cv::Scalar(0),10);

        //update edge positions and distance transform
        edgePositions = getPointPositions(mask);
        cv::distanceTransform(255-mask, dt,CV_DIST_L1, 3);
    }

    cv::Mat tmp;
    mask.copyTo(tmp);

    // prevent cases where no fircle could be extracted (because three points collinear or sth.)
    // filter NaN values
    if((center.x == center.x)&&(center.y == center.y)&&(radius == radius))
    {
        cv::circle(tmp,center,radius,cv::Scalar(255));
    }
    else
    {
        std::cout << "circle illegal" << std::endl;
    }

    ++nIterations;
    cv::namedWindow("RANSAC"); cv::imshow("RANSAC", tmp);
}

std::cout << nIterations <<  " iterations performed" << std::endl;


cv::namedWindow("edges"); cv::imshow("edges", mask);
cv::namedWindow("color"); cv::imshow("color", color);

cv::imwrite("detectedCircles.png", color);
cv::waitKey(-1);
return 0;
}


float verifyCircle(cv::Mat dt, cv::Point2f center, float radius, std::vector<cv::Point2f> & inlierSet)
{
 unsigned int counter = 0;
 unsigned int inlier = 0;
 float minInlierDist = 2.0f;
 float maxInlierDistMax = 100.0f;
 float maxInlierDist = radius/25.0f;
 if(maxInlierDist<minInlierDist) maxInlierDist = minInlierDist;
 if(maxInlierDist>maxInlierDistMax) maxInlierDist = maxInlierDistMax;

 // choose samples along the circle and count inlier percentage
 for(float t =0; t<2*3.14159265359f; t+= 0.05f)
 {
     counter++;
     float cX = radius*cos(t) + center.x;
     float cY = radius*sin(t) + center.y;

     if(cX < dt.cols)
     if(cX >= 0)
     if(cY < dt.rows)
     if(cY >= 0)
     if(dt.at<float>(cY,cX) < maxInlierDist)
     {
        inlier++;
        inlierSet.push_back(cv::Point2f(cX,cY));
     }
 }

 return (float)inlier/float(counter);
}


inline void getCircle(cv::Point2f& p1,cv::Point2f& p2,cv::Point2f& p3, cv::Point2f& center, float& radius)
{
  float x1 = p1.x;
  float x2 = p2.x;
  float x3 = p3.x;

  float y1 = p1.y;
  float y2 = p2.y;
  float y3 = p3.y;

  // PLEASE CHECK FOR TYPOS IN THE FORMULA :)
  center.x = (x1*x1+y1*y1)*(y2-y3) + (x2*x2+y2*y2)*(y3-y1) + (x3*x3+y3*y3)*(y1-y2);
  center.x /= ( 2*(x1*(y2-y3) - y1*(x2-x3) + x2*y3 - x3*y2) );

  center.y = (x1*x1 + y1*y1)*(x3-x2) + (x2*x2+y2*y2)*(x1-x3) + (x3*x3 + y3*y3)*(x2-x1);
  center.y /= ( 2*(x1*(y2-y3) - y1*(x2-x3) + x2*y3 - x3*y2) );

  radius = sqrt((center.x-x1)*(center.x-x1) + (center.y-y1)*(center.y-y1));
}



std::vector<cv::Point2f> getPointPositions(cv::Mat binaryImage)
{
 std::vector<cv::Point2f> pointPositions;

 for(unsigned int y=0; y<binaryImage.rows; ++y)
 {
     //unsigned char* rowPtr = binaryImage.ptr<unsigned char>(y);
     for(unsigned int x=0; x<binaryImage.cols; ++x)
     {
         //if(rowPtr[x] > 0) pointPositions.push_back(cv::Point2i(x,y));
         if(binaryImage.at<unsigned char>(y,x) > 0) pointPositions.push_back(cv::Point2f(x,y));
     }
 }

 return pointPositions;
}

这篇关于使用 OpenCV 和 Python 检测图像中的弧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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