Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/math/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OpenCV检测带有噪声的部分圆_Opencv_Geometry - Fatal编程技术网

OpenCV检测带有噪声的部分圆

OpenCV检测带有噪声的部分圆,opencv,geometry,Opencv,Geometry,我曾尝试使用OpenCV HoughCircles和FindContentours来检测圆,但是圆不够完整,或者这些算法的算法中存在太多的噪声。或者我们对OpenCV还不够熟悉。附件是我的图片,我需要找到上面的圆圈。您应该能够用眼睛清楚地看到它,但是,所有的圆检测算法似乎都不起作用。我发现应用中值滤波可以清除大部分噪声,但即使在中值滤波之后,算法也无法检测到圆 注意,我甚至在这里查看并尝试了解决方案,因此它不是该问题的重复: 有什么想法吗?这是我需要使用的源图像 另外,我想检测圆的原因是我想只

我曾尝试使用OpenCV HoughCircles和FindContentours来检测圆,但是圆不够完整,或者这些算法的算法中存在太多的噪声。或者我们对OpenCV还不够熟悉。附件是我的图片,我需要找到上面的圆圈。您应该能够用眼睛清楚地看到它,但是,所有的圆检测算法似乎都不起作用。我发现应用中值滤波可以清除大部分噪声,但即使在中值滤波之后,算法也无法检测到圆

注意,我甚至在这里查看并尝试了解决方案,因此它不是该问题的重复:

有什么想法吗?这是我需要使用的源图像

另外,我想检测圆的原因是我想只使用圆的一部分的点进行计算

原始图像:

中值滤波图像:

嗯。。。。如果你把图像的对比度提高一点,你就会得到这个

我认为大多数算法都会与之斗争。由于实际圆相对于其他(大概是)不需要的东西是相当亮的,可能考虑在值200附近某个阈值。

< P>这里,你走:

我正在使用我的第二个答案,并对其稍加修改。该版本现在检测到最佳半圆(关于完整性)

但首先,我想告诉你们为什么被接受的答案在这里不起作用(除了噪音):你们只有圆的边!如问题中所述,Houghcirle函数在内部计算梯度,这对边缘图像不起作用

但现在我怎么做:

使用此作为输入(您自己的中值滤波图像(我刚刚裁剪过):

首先,我对图像进行“标准化”,我只是拉伸值,最小的值是0,最大的值是255,结果是:(可能一些真实的对比度增强效果更好)

之后,我用一些固定的阈值计算该图像的阈值(您可能需要编辑该阈值,并找到一种动态选择阈值的方法!更好的对比度增强可能会有所帮助)

从这张图片中,我使用了一些简单的RANSAC圆检测(与我在链接的半圆检测问题中的回答非常相似),将此结果作为最佳的半圆:

下面是代码:

int main()
{
    //cv::Mat color = cv::imread("../inputData/semi_circle_contrast.png");
    cv::Mat color = cv::imread("../inputData/semi_circle_median.png");
    cv::Mat gray;

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

    // now map brightest pixel to 255 and smalles pixel val to 0. this is for easier finding of threshold
    double min, max;
    cv::minMaxLoc(gray,&min,&max);
    float sub = min;
    float mult = 255.0f/(float)(max-sub);
    cv::Mat normalized = gray - sub;
    normalized = mult * normalized;
    cv::imshow("normalized" , normalized);
    //--------------------------------


    // now compute threshold
    // TODO: this might ne a tricky task if noise differs...
    cv::Mat mask;
    //cv::threshold(input, mask, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    cv::threshold(normalized, mask, 100, 255, CV_THRESH_BINARY);



    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;

    cv::Point2f bestCircleCenter;
    float bestCircleRadius;
    float bestCirclePercentage = 0;
    float minRadius = 50;   // TODO: ADJUST THIS PARAMETER TO YOUR NEEDS, otherwise smaller circles wont be detected or "small noise circles" will have a high percentage of completion

    //float minCirclePercentage = 0.2f;
    float minCirclePercentage = 0.05f;  // at least 5% of a circle must be present? maybe more...

    int maxNrOfIterations = edgePositions.size();   // TODO: adjust this parameter or include some real ransac criteria with inlier/outlier percentages to decide when to stop

    for(unsigned int its=0; its< maxNrOfIterations; ++its)
    {
        //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);

        // 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);

        // update best circle information if necessary
        if(cPerc >= bestCirclePercentage)
            if(radius >= minRadius)
        {
            bestCirclePercentage = cPerc;
            bestCircleRadius = radius;
            bestCircleCenter = center;
        }

    }

    // draw if good circle was found
    if(bestCirclePercentage >= minCirclePercentage)
        if(bestCircleRadius >= minRadius);
        cv::circle(color, bestCircleCenter,bestCircleRadius, cv::Scalar(255,255,0),1);


        cv::imshow("output",color);
        cv::imshow("mask",mask);
        cv::waitKey(0);

        return 0;
    }
intmain()
{
//cv::Mat color=cv::imread(../inputData/semi_circle_contrast.png”);
cv::Mat color=cv::imread(../inputData/semi_circle_median.png”);
cv::席灰色;
//转换为灰度
cv::CVT颜色(颜色、灰色、cv_bgr2灰色);
//现在将最亮的像素映射到255,将最小像素值映射到0。这是为了更容易找到阈值
双最小值,最大值;
cv::minMaxLoc(灰色、最小值和最大值);
浮子=最小值;
浮动倍数=255.0f/(浮动)(最大分压);
cv::Mat归一化=灰色-子;
标准化=多个*标准化;
cv::imshow(“标准化”,标准化);
//--------------------------------
//现在计算阈值
//TODO:如果噪音不同,这可能是一项棘手的任务。。。
cv::Mat面罩;
//cv::阈值(输入,掩码,0,255,cv_THRESH_BINARY | cv_THRESH_OTSU);
cv::阈值(标准化,掩码,100255,cv_阈值_二进制);
std::矢量边缘定位;
边位置=获取点位置(掩码);
//创建距离变换以有效计算到最近边的距离
cv::Mat dt;
cv::距离变换(255掩码,dt,cv_距离_L1,3);
//TODO:可能是实数随机数的种子随机变量。
无符号整数运算=0;
cv::Point2f bestCircleCenter;
漂浮性斜视;
float bestCirclePercentage=0;
float minRadius=50;//TODO:根据您的需要调整此参数,否则将无法检测到较小的圆,或者“小噪音圆”将具有较高的完成百分比
//浮动最小循环百分比=0.2f;
float minCirclePercentage=0.05f;//必须至少有5%的圆存在?可能更多。。。
int maxnrofitrations=edgePositions.size();//TODO:调整此参数或包含一些实际的ransac标准,其中包含更高/更离群的百分比,以决定何时停止
for(无符号int-its=0;its=bestCirclePercentage)
如果(半径>=最小半径)
{
bestCirclePercentage=cPerc;
bestCircleRadius=半径;
bestCircleCenter=中心;
}
}
//如果找到好的圆圈,则绘制
if(最佳圈百分比>=最小圈百分比)
如果(bestCircleRadius>=最小半径);
cv::circle(颜色,bestCircleCenter,bestCircleRadius,cv::Scalar(255255,0),1);
cv::imshow(“输出”,颜色);
cv::imshow(“面具”,面具);
cv::waitKey(0);
返回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;
}
Mat img;
img = imread("iokqh.png");

if (img.empty())
{
    cout << "Could not open image..." << endl;
    return -1;
}

cvtColor(img, img, COLOR_BGR2GRAY);

int dilation_type = 0;
int dilation_elem = 0;

if (dilation_elem == 0) { dilation_type = MORPH_RECT; }
else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }
else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

int size = 1;

Mat element = getStructuringElement(dilation_type, Size(2 * size + 1, 2 * size + 1), Point(size, size));
morphologyEx(img, img, MORPH_OPEN, element);

vector<Point2f> points;
for (int x = 0; x < img.cols; x++)
{
    for (int y = 0; y < img.rows; y++)
    {
        if (img.at<uchar>(y, x) > 0)
        {
            points.push_back(cv::Point2f(x, y));
        }
    }
}

//// Least Square Algorithm 

float xn = 0, xsum = 0;
float yn = 0, ysum = 0;
float n = points.size();

for (int i = 0; i < n; i++)
{
    xsum = xsum + points[i].x;
    ysum = ysum + points[i].y;
}

xn = xsum / n;
yn = ysum / n;

float ui = 0;
float vi = 0;
float suu = 0, suuu = 0;
float svv = 0, svvv = 0;
float suv = 0;
float suvv = 0, svuu = 0;

for (int i = 0; i < n; i++)
{
    ui = points[i].x - xn;
    vi = points[i].y - yn;

    suu = suu + (ui * ui);
    suuu = suuu + (ui * ui * ui);

    svv = svv + (vi * vi);
    svvv = svvv + (vi * vi * vi);

    suv = suv + (ui * vi);

    suvv = suvv + (ui * vi * vi);
    svuu = svuu + (vi * ui * ui);
}

cv::Mat A = (cv::Mat_<float>(2, 2) <<
    suu, suv,
    suv, svv);

cv::Mat B = (cv::Mat_<float>(2, 1) <<
    0.5*(suuu + suvv),
    0.5*(svvv + svuu));

cv::Mat abc;
cv::solve(A, B, abc);

float u = abc.at<float>(0);
float v = abc.at<float>(1);

float x = u + xn;
float y = v + yn;

float alpha = u * u + v * v + ((suu + svv) / n);
float r = sqrt(alpha);

////

cvtColor(img, img, COLOR_GRAY2BGR);

// Draw circle
circle(img, Point(x, y), r, Scalar(255, 0, 0), 1, 8, 0);
imshow("window", img);
waitKey(0);