我正在尝试使用ROI
和Gaussian filter
软件模糊图像中的imageJ
。
我在blur radius as 9
中获得了imageJ
所需的结果。
现在我正在尝试编写相应的OpenCV C++ application
来执行与imageJ
相同的操作。
Gaussian Blur
中的openCV
签名如下:
C++: void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
与sigmaX
对应的sigmaY
和ImageJ blur radius of 9
是什么?
我尝试了很多资源,例如: Blur Radius
但我与OpenCV
没有得到相同的结果。
答案 0 :(得分:0)
请您详细说明结果如何"不一样" ?
ImageJ中的模糊半径定义为"' Radius'表示衰减半径为exp(-0.5)~61%,即高斯的标准偏差西格玛" (来自ImageJ文档:https://imagej.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html#GaussianBlur--) 我认为没有理由不在OpenCV中以相同的方式实现它。
然而,我也观察到ImageJ和OpenCV高斯模糊之间的这些差异。 虽然目前我没有解决办法使这些绝对相同,但我设法让它们更接近,并且可以看到一个潜在的差异和一个差异,以确保实施:
内核大小(潜在差异): 你知道内核大小和高斯半径是两个不同的东西吗?内核大小是应用于图像的内核的大小(3 * 3,5 * 5等),但是在这个内核中,任何半径的高斯都可以存在。然而,内核大小经常被选中,使得在内核边界上,高斯函数已经衰减到大约零。
话虽如此,ImageJ会根据您选择的半径自动为您选择内核,以便在边界上实现高斯衰减为零#34;条件。如果您将sigma设置为所需的半径并将ksize设置为零,则OpenCV函数也会执行此操作。问题是"他们都以同样的方式做到了吗?"。
ImageJ的实现比你想象的更棘手:"在ImageJ中,实际使用的内核大小取决于准确性 需要:使用sigma = 1,对于16位和浮点图像,内核为9像素 宽(对于2D图像给出9x9),但对于8位或RGB图像是 只有7像素宽,因为如果不需要非常高的精度 只有256个不同的值。对于较大的sigma值,情况更复杂:对于sigma> = 8,首先缩小数据,然后应用高斯模糊,并使用插值来放大到原始数据点数。降尺度和插值算法是专门为最高精度设计的。"等等(来自" ImageJ论坛",我不能发布链接,因为我没有足够的声誉,但只要谷歌这个引用,如果你想要源)
我不知道OpenCV是否执行此类操作,或者它是否以不同方式计算内核大小,从而产生不同的结果。 (无法通过Google找到它。)
边框(确定不同):您可能知道,高斯滤镜会遍历图像中的每个像素,并根据其邻居计算此像素的新值。但是接近边界的像素呢,高斯核比距离图像边界的距离宽?算法如何处理它?通过更仔细地检查我的图像,我发现OCV实现和IJ之间的主要区别在于边界像素。
事实证明,ImageJ和OpenCV处理这些像素的方式不同:
ImageJ高斯,"与ImageJ中的所有卷积运算一样,它假设图像外像素的值等于最近的边缘像素。" (来自与上面相同的ImageJ文档)。
但是,OpenCV允许您选择其他选项,而OpenCV调用中名为BORDER_DEFAULT
的默认选项为BORDER_REFLECT_101
(http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.html)(至少我认为是,它是使用边框的另一种方法的默认边框,所以我认为它也是高斯的默认边框)。 BORDER_REFLECT_101
种"镜像"边界(gfedcb | abcdefgh,见链接)。
要靠近ImageJ(aaaaaaaa | abcdefgh),请使用BORDER_DEFAULT=BORDER_REPLICATE
。有了这个,我在两个实现之间得到了更接近的结果(尽管不完全相同,如果我找到更多线索,我将继续调查和编辑我的答案)。
[注意:我使用的是Python2.7(不是C ++)和OpenCV 3,但我认为它不会对这个问题产生影响]