Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.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
C++ opencv:在二值图像中拟合最小封闭椭圆_C++_Opencv_Image Processing - Fatal编程技术网

C++ opencv:在二值图像中拟合最小封闭椭圆

C++ opencv:在二值图像中拟合最小封闭椭圆,c++,opencv,image-processing,C++,Opencv,Image Processing,我使用OpenCV和grabcut实现生成前景的二进制掩码。这表示为CV_8UC1的opencv矩阵,其中属于前景的像素值为255,背景为零(即,它是一个二进制掩码)。因此,一个像所附图像一样的图像: 我想找到这个蒙版图像的最小封闭椭圆。我在网上找到的例子似乎有点复杂,我无法将其转化为我的需要。我试着简单地使用 // result is my OpenCV array of cv::RotatedRect e = cv::fitEllipse(result); OpenCV Error: A

我使用OpenCV和grabcut实现生成前景的二进制掩码。这表示为CV_8UC1的opencv矩阵,其中属于前景的像素值为255,背景为零(即,它是一个二进制掩码)。因此,一个像所附图像一样的图像:

我想找到这个蒙版图像的最小封闭椭圆。我在网上找到的例子似乎有点复杂,我无法将其转化为我的需要。我试着简单地使用

// result is my OpenCV array of 
cv::RotatedRect e = cv::fitEllipse(result);

OpenCV Error: Assertion failed (points.checkVector(2) >= 0 && 
(points.depth() == CV_32F || points.depth() == CV_32S)) in fitEllipse, 
file /home/luca/Downloads/opencv-2.4.10/modules/imgproc
/src/contours.cpp, line 2019

terminate called after throwing an instance of 'cv::Exception'
what():  /home/luca/Downloads/opencv-2.4.10/modules/imgproc
/src/contours.cpp:2019: error: (-215) points.checkVector(2) >= 0 && 
(points.depth() == CV_32F || points.depth() == CV_32S) in function 
fitEllipse
即使使用以下命令将其转换为32位带符号整数,错误仍然存在:

cv::Mat r;
result.convertTo(r, CV_32S);
cv::RotatedRect e = cv::fitEllipse(r);

好的,我知道了。我需要把它转换成一个轮廓集。代码取自在线示例

cv::vector<cv::vector<cv::Point> > contours;
cv::findContours(result, contours, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
// Assuming always returns one contour as the input is binary
cv::RotatedRect box = cv::fitEllipse(contours[0]);
// Draw the ellipse
cv::ellipse(image, box, cv::Scalar(255,0,0));
cv::矢量轮廓;
cv::findContours(结果、轮廓、cv::RETR\u列表、cv::CHAIN\u近似值\u无);
//假设始终返回一个轮廓,因为输入是二进制的
cv::RotatedRect box=cv::fitEllipse(等高线[0]);
//画椭圆
cv::椭圆(图像,长方体,cv::标量(255,0,0));
该函数获取cv::Point s数组,而不是图像。所以你想先把你的图像扫描一遍。请注意,
findContours
会修改图像,因此您可能需要先进行复制

std::vector< std::vector<cv::Point> > contours;
cv::Mat tmp = result.clone();
cv::findContours(tmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); // edited to change from CV_CHAIN_APPROX_SIMPLE
cv::RotatedRect e = cv::fitEllipse(contours[0]);
std::vector等高线;
cv::Mat tmp=result.clone();
cv::findContours(tmp、轮廓、cv_RETR_外部、cv_CHAIN_近似值_NONE);//编辑以从CV\u链\u近似值\u简单更改
cv::RotatedRect e=cv::fitEllipse(等高线[0]);

以上假设图像中只有一个轮廓。如果存在任何噪声(并验证至少获得一个轮廓),您可能需要搜索
轮廓
,以查找最大轮廓(使用大小或面积)。

如果您不确定图像中是否有椭圆,可以通过调用
cv::Minareact
使用另一种方法

我已经为3种不同的方式编写了示例代码:

1. call cv::fitEllipse
2. call cv::minAreaRect
3. call cv::fitEllipse on contour only
代码有点凌乱,但不管怎样,它可能会有所帮助

int main()
{
    cv::Mat input = cv::imread("../inputData/fitEllipseMask.jpg");

    cv::Mat gray;
    cv::cvtColor(input,gray,CV_BGR2GRAY);
    cv::Mat mask = gray > 200; // remove jpeg artifacts

    std::vector<cv::Point> pts;

    for(int j=0; j<mask.rows; ++j)
        for(int i=0; i<mask.cols; ++i)
        {
            if(mask.at<unsigned char>(j,i))
            {
                pts.push_back(cv::Point(i,j));
            }
        }

    cv::RotatedRect result1 = cv::fitEllipse(pts);
    cv::ellipse(input, result1, cv::Scalar(0,255,0) ,3  );

    cv::RotatedRect result2 = cv::minAreaRect(pts);
    cv::ellipse(input, result2, cv::Scalar(0,0,255) ,3 );


    // now a third method to fit an ellipse but only the contour of the mask object

    // edges could be extracted with findContours instead which might or might not be better, depending on input images
    cv::Mat magX, absmagx;
    cv::Sobel(mask, magX, CV_32FC1, 1, 0);
    cv::convertScaleAbs( magX, absmagx );

    cv::Mat magY, absmagy;
    cv::Sobel(mask, magY, CV_32FC1, 0, 1);
    cv::convertScaleAbs( magY, absmagy );

    cv::Mat mag = absmagx+absmagy;

    cv::Mat edgeMask = mag > 0;

    cv::imshow("edges",edgeMask);


    std::vector<cv::Point> ptsEdges;

    for(int j=0; j<edgeMask.rows; ++j)
        for(int i=0; i<edgeMask.cols; ++i)
        {
            if(edgeMask.at<unsigned char>(j,i))
            {
                ptsEdges.push_back(cv::Point(i,j));
            }
        }

    cv::RotatedRect result3 = cv::fitEllipse(ptsEdges);
    cv::ellipse(input, result3, cv::Scalar(255,0,0) , 3  );


    cv::namedWindow("input");
    cv::imshow("input", input);
    //cv::imwrite("../outputData/MainBase.png", input);
    cv::waitKey(0);
    return 0;
}

转换后的错误是什么?如果这是相同的错误,那么转换可能做得不好。fitEllipse不会创建边界框(MineConclosing)椭圆,但会找到一组轮廓点最能描述的椭圆。这是非常不同的。此外,我猜输入应该是点的向量。看起来我不够快:-)请注意,将cv::Point s的向量转换为cv::Mat是不必要的。没错。谢谢你的提示。我刚从样品中复制了这个东西。抱歉,这还是个新问题。请注意,
CV\u-CHAIN\u-APPROX\u-SIMPLE
可能是安装任务的一个问题。而在椭圆拟合中,近似轮廓的可能性不大。通常情况下,可能会将所需轮廓减少到几个点,而噪波可能会获得更多样本,这会分散拟合算法的注意力。但正如我所说的,对于椭圆来说,我想不会有什么问题,因为可能使用
cv::minareact
来代替它没有什么好的地方。我发现,如果要拟合的水滴不一定是一个好的椭圆,那么效果会更好。不幸的是,它并不总是包围整个对象(但相应的矩形确实如此)
1. green: since we try to fit the ellipse to the whole white region, the best found ellipse is something like the mean ellipse within the region
2. red: not as good as 3 but will give better results if there is no ellipse in the image but another object
3. blue: fitting an ellipse to a real ellipse with some outliers/noise is just the best result ;)