CvInvoke.Canny() - 在不同的计算机上产生不同的结果

4

当我在不同的电脑(和显示器)上尝试对同一图像文件执行一些二进制操作时,使用CvInvoke.Canny()方法时会得到不同的结果。
在调用此方法之前,我使用了几种操纵方法,例如:CvInvoke.Threshold()CvInvoke.Erode()CvInvoke.Dilate()等等...... 所有这些的结果始终相等。
只有当我调用:

UMat inputImageUMAT = new Image<Gray, byte>(inputImageBitmap).ToUMat();
UMat imageUmat = new UMat();
CvInvoke.Threshold(imageInputUMAT, imageUmat, threshold, 255, 
Emgu.CV.CvEnum.ThresholdType.Binary);

// clear noises with Erode & Dilate:
CvInvoke.Erode(imageUmat, imageUmat, null, new Point(-1, -1), 1, 
BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);
CvInvoke.Dilate(imageUmat, imageUmat, null, new Point(-1, -1), 1, 
BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);

//use image pyr to remove noise:
UMat pyrDown = new UMat();
CvInvoke.PyrDown(imageUmat, pyrDown);
CvInvoke.PyrUp(pyrDown, imageUmat);

 // set cannyEdges to hold the outlines of the shapes detected in the image 
(according to threshold) 
UMat cannyEdges = new UMat();
CvInvoke.Canny(imageUmat, cannyEdges, threshold, threshold);
不同计算机输出总是存在差异。
尽管如此,每台计算机始终会给出完全相同的结果-一次又一次。

可能是什么原因导致了这个问题?
我必须在任何地方获得完全相同的结果...

p.s.
我使用C# Nuget:EMGU.CV v3.3.0.2824

编辑:
我拿到了原始文件:original
并跳过了整个过程中的所有操作,并立即执行了 Canny

UMat inputImageUMAT = new UMat(fileName, ImreadModes.Grayscale);
UMat cannyEdges = new UMat();
CvInvoke.Canny(imageInputUMAT, cannyEdges, threshold, threshold, 3, true);
cannyEdges.Save(outputFileName);

阈值为210的结果,机器1:结果1
阈值为210的结果,机器2:结果2
-- 两个结果之间有一个像素的差异。


同样的代码在同一台机器上运行多次,输出结果是否会有所变化? - Dmitrii Z.
在任何机器上,结果始终相同。 - RedHat
我不确定我理解你所要求的内容。 我已经将UMAT保存为“.bmp”格式,每一步都进行了比较,使用了“Beyond Compare”工具。我不知道如何加载不同的文件 - 但我会查看这个问题。 - RedHat
1
不同的解码器实现可能导致不同的结果。为了确保这种情况不会发生,建议不要对输入文件使用任何压缩。因此,在调用“Canny”之前,只需保存您的图像,并将结果馈送到2台机器上的“Canny”,将输出保存为图像并将它们放入您的问题中。 - Dmitrii Z.
1
非常感谢@DmitriiZ。我添加了文件并跳过了所有压缩,有什么区别的建议吗? - RedHat
显示剩余3条评论
2个回答

2
我已经写信给EMGU的支持团队,他们的回答非常出色:

我查看了你的代码,发现它使用UMat。这意味着当OpenCL(GPU)可用时,代码将使用它来加速处理,并在没有兼容的OpenCL驱动程序/设备的工作站上退回到CPU。
我怀疑OpenCL路径产生的结果与CPU路径略有不同。在调用代码中的任何Emgu CV函数之前,请尝试添加以下行并检查是否使结果在所有计算机上保持一致:

CvInvoke.UseOpenCL = false

以上代码将禁用OpenCL并强制所有代码在CPU上运行。

毫不奇怪-他们是对的。真的解决了问题。

0

好的。
我不能说我完全理解了问题的原因,但我肯定已经在所有计算机之间稳定了它。
问题在于,起初我使用了静态方法CvInvoke.Canny()并发送了输入和输出Umat - 它可能不确定原始图像的类型,然后(通过访问一些windows dll或优先级或其他东西?)导致每台计算机上的不同决策,因此不同的Umat翻译会导致不同的结果。
(...也许)

但是
当我将输入图像加载到Image<Gray,Byte>中并使用它自己的Canny方法(以及其他方法)时 - 所有内容都是稳定的,无论在哪台计算机上运行
所以工作代码是:

UMat inputImageUMAT = new Image<Gray, byte>(inputFileName).ToUMat();
Image<Gray, Byte> binaryImage = inputImageUMAT.ToImage<Gray,Byte>().ThresholdBinary(new Gray(threshold), new Gray(255));
binaryImage = binaryImage.Erode(1);
binaryImage = binaryImage.Dilate(1);
binaryImage = binaryImage.PyrDown();
binaryImage = binaryImage.PyrUp();
binaryImage = binaryImage.Canny(1, 0, 3, true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接