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

CvInvoke.Canny() - gives different results on different computers

当尝试对完全相同的图像文件执行一些二进制操作时,但在不同的计算机(和显示器)上,使用 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# 块: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 的结果:result_1
阈值 210 机器 2 的结果:result_2
-- 2个结果之间有1个像素的差异

好的。
我不能说我已经 100% 理解问题的原因,但我肯定在所有计算机之间都保持稳定。
问题是,起初我使用静态方法 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);

我已经写信给 EMGU 的支持,这是他们惊人的答复:

I reviewed your code and it is using UMat. That means that the code will using OpenCL (GPU) to speed up the processing when it is available and fall back to CPU for workstation where there is no compatible OpenCL driver / device.
My suspicion is that the result produced by the OpenCL path is slightly different from the CPU path. Can you the following line before calling any of the Emgu CV function in your code and check if that make the result consistent across the machines:

CvInvoke.UseOpenCL = false

The above code will disable OpenCL and force all the code to run on CPU

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