OPENCV C 和 C++ API 结果不同(边界插值差异)

Posted

技术标签:

【中文标题】OPENCV C 和 C++ API 结果不同(边界插值差异)【英文标题】:Different result with OPENCV C and C++ API (Border Interpolation difference) 【发布时间】:2012-08-01 22:00:18 【问题描述】:

我已经执行了闭合形态学操作,并且使用 C 和 C++ API (OpenCV 2.4.2) 得到了不同的结果

输入:

使用 OpenCV 'C':

//Set ROI
//Perform Gaussian smoothing
//Perform Canny edge analysis
cvMorphologyEx( src, dst, temp, Mat(), MORPH_CLOSE, 5 );

结果: http://i47.tinypic.com/33e0yfb.png

使用 Opencv C++

//Set ROI 
//Perform Gaussian smoothing 
//Perform Canny edge analysis
cv::morphologyEx( src, dst, cv::MORPH_CLOSE, cv::Mat(), cv::Point(-1,-1), 5 );

结果: http://i50.tinypic.com/i5vxjo.png

如您所见,C++ API 生成带有白色/灰色边框颜色的输出。因此,这两种 API 的结果是不同的。

我用 C++ API 尝试了不同的borderType,但总是产生相同的结果。

如何在 C++ 中获得与 C API 相同的输出?我需要它,因为它会影响检测到的轮廓

提前致谢

【问题讨论】:

能把原图加进去吗? @HåvardGeithus:输入:i47.tinypic.com/9kthzm.png;如图所示,输入图像是一个精巧的边缘输出。 【参考方案1】:

感谢大家回答这个问题。我发现了我的错误。我将在下面简要描述它。希望它可以帮助其他面临这个问题的人。

1) 我在 ROI 图像上执行了 C 和 C++ 命令。显然,OpenCV 'C' 和 'C++' API 对待 ROI 的方式是不同的。

2) 在“C”中,ROI 被视为完全不同的图像。因此,当您执行诸如 cvSmooth、cvDilate 等需要提及边界像素外推方法的函数时,“C”API 不会针对超出左/右/顶部/底部最像素的像素返回原始图像。它实际上是根据您提到的方法对像素值进行插值。

3) 但在“C++”中,我发现它总是引用原始图像来获取超出左/右/顶部/底部最像素的像素。因此,如果您的 ROI 周围的原始图像中有像素,则提到的边界像素外推方法不会影响您的输出。

我认为它将顺序像素外推方法应用于原始图像而不是 ROI,这与“C”API 不同。我不知道这是否是一个错误;我还没有完全阅读 OpenCV 2.4.2 C++ API 文档。 (如有错误请指正)

为了获得我的支持,我在下面发布了输入/输出图像:

“C”和 C++ API 的输出:

输入:

OpenCV 'C' API

IplImage *src = cvLoadImage("input.png", 0);
cvSetImageROI( src, cvRect(33,19,250,110)); 
cvSaveImage( "before_gauss.png", src );
cvSmooth( src, src, CV_GAUSSIAN );  
cvSaveImage("after_gauss.png", src);
IplConvKernel *element = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT);
cvCanny( src, src, 140, 40 );
cvSaveImage("after_canny.png", src);
cvDilate( src, src, element, 5);
cvSaveImage("dilate.png", src);

输出:

OpenCV 'C++' API

cv::Mat src = cv::imread("input.png", 0);
cv::Mat src_ROI = src( cv::Rect(33,19,250,110));
cv::imwrite( "before_gauss.png", src_ROI );
cv::GaussianBlur( src_ROI, src_ROI, cv::Size(3,3),0 );
cv::imwrite( "after_gauss.png", src_ROI ); 
cv::Mat element = cv::getStructuringElement( cv::MORPH_RECT, cv::Size(3, 3), cv::Point(1,1));
cv::Canny( src_ROI, src_ROI, 140, 40);
cv::imwrite( "after_canny.png", src_ROI );
cv::dilate( src_ROI, src_ROI, element, cv::Point(1,1), 5);
cv::imwrite( "dilate.png", src_ROI );

输出:

^^^^^ after_gauss(注意:边框不再是全黑,而是灰色)

^^^^^ after_canny

^^^^^ 扩张

解决方案:

创建一个单独的 ROI 副本并将其用于进一步分析;

src_ROI.copyTo( new_src_ROI ); 

使用 new_src_ROI 进行进一步分析。 如果有人有更好的解决方案,请在下面发布

【讨论】:

【参考方案2】:

默认值在 C 和 C++ 之间是不同的——尤其是结构元素。 在 C 中:默认的结构元素是:

cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT)

而在 C++ 中,默认的结构元素是:

getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));

如果您想要相同的结果,您应该指定所有字段(包括锚点)。

【讨论】:

结构元素也是我的第一个想法。 @go4sri : 这次我将结构元素构造为 cv::getStructuringElement( cv::MORPH_RECT, cv::Size(3, 3), cv::Point(1,1) ) ;我仍然得到不同的结果:i45.tinypic.com/2j4x47q.png;接下来我只尝试了扩张扩张结果:i48.tinypic.com/10o20ky.png;如您所见,四面都有白色边框。这不应该是这样吧?我尝试更改borderType,但它总是产生相同的结果 @HåvardGeithus:形态闭合:cv::morphologyEx(src, src, cv::MORPH_CLOSE, structuringElement, cv::Point(1, 1), 5);【参考方案3】:

查看 OpenCV v2.4.2 文档中的 sample code。您可能还想查看 this code 以了解使用 Canny 边缘检测器。这些希望能帮助您找出错误:)

还要注意,形态闭合是幂等算子,因此可以多次应用,而不会改变初始应用后的结果。

【讨论】:

以上是关于OPENCV C 和 C++ API 结果不同(边界插值差异)的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow 对象检测在 Python 和 C++(OpenCV) 之间有不同的结果

c++中的opencv convertTo和Python中的手动转换结果不同

opencv c++ kmeans 和 matlab kmeans 的不同结果

C语言或者C++如何调用一个http接口并得到返回结果?

相同算法的 C++ 和 Python 版本给出不同的结果

正确包括在 opencv 2.3 中使用新的 C++ API