当尝试对完全相同的图像文件执行一些二进制操作时,但在不同的计算机(和显示器)上,使用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.i
使用 C# nugget: EMGU。CV v3.3.0.2824
编辑:我拿了原始文件:
原始
文件并跳过了途中的所有操作,并立即执行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:阈值为 210 的result_1
结果 机器 2:result_2
-- 2 个结果之间存在 1 个像素的差异
我已经写信给EMGU的支持,这是他们的惊人答案:
我查看了您的代码,它正在使用 UMat。这意味着代码将使用 OpenCL (GPU) 在可用时加快处理速度,并在没有兼容的 OpenCL 驱动程序/设备的工作站回退到 CPU。
我怀疑 OpenCL 路径产生的结果与 CPU 路径略有不同。在调用代码中的任何 Emgu CV 函数之前,您能否完成以下行,并检查这是否使结果在机器上保持一致:
CvInvoke.UseOpenCL = false
上面的代码将禁用 OpenCL 并强制所有代码在 中央处理器
毫不奇怪 - 他们是对的。它确实解决了这个问题。
好的,
我不能说我已经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);