双线性插值 – DirectX与GDI +

我有一个C#应用程序,我已经编写了GDI +代码,它使用Bitmap / TextureBrush渲染来呈现2D图像,这些图像可以应用各种图像处理function。 此代码是模拟现有DX9代码的应用程序中的新路径,它们共享一个公共库以执行所有向量和矩阵(例如ViewToWorld / WorldToView)操作。 我的测试床由DX9输出图像组成,我将其与新GDI +代码的输出进行比较。

渲染到与Bitmap尺寸匹配的视口(即没有缩放或平移)的简单测试用例确实匹配像素完美(没有二进制差异) – 但是一旦图像被放大(放大),我就会得到非常小的差异在5-10%的像素中。 差异的大小是1(偶尔2)/ 256。 我怀疑这是由于插值差异造成的。

问题 :对于DX9正射投影(和身份世界空间),相机垂直并以纹理四边形为中心,期望DirectX.Direct3D.TextureFilter.Linear生成相同的输出到GDI + TextureBrush填充的矩形/多边形是合理的使用System.Drawing.Drawing2D.InterpolationMode.Bilinear设置?

对于这个(放大)情况,DX9代码正在使用它(MinFilter,MipFilter设置类似):
Device.SetSamplerState(0, SamplerStageStates.MagFilter, (int)TextureFilter.Linear);

并且GDI +路径正在使用: g.InterpolationMode = InterpolationMode.Bilinear;

我认为“双线性插值”是一个相当具体的滤波器定义,但后来我注意到GDI +中还有另一种选择“HighQualityBilinear”(我尝试过,没有区别 – 考虑到“添加预滤波”的描述,这是有道理的缩小“)

后续问题:期望DirectX和GDI +之间的像素完美输出匹配是否合理(假设传入的所有外部坐标相等)? 如果没有,为什么不呢?

澄清:我正在使用的图像是使用Format32bppPArgb的不透明灰度(R = G = B,A = 1)。

最后,我可以使用许多其他API(Direct2D,WPF,GDI等) – 这个问题通常适用于比较“等效”双线性插值输出图像的输出。 谢谢!

DirectX主要在GPU中运行,而DX9可能正在运行着色器。 GDI +运行完全不同的算法。 我不认为期望两者提出精确的像素匹配输出是合理的。

我认为DX9的质量要比GDI +好,这比旧的GDI有所改进,但并不多。 人们早就知道GDI +在抗锯齿线方面存在问题,并且在图像缩放方面也保持了质量(这似乎是你的问题)。 为了获得与最新一代GPU纹理处理相似的质量,您需要转移到WPF图形。 这提供了与DX类似的质量。

WPF还使用GPU(如果可用)并回退到软件渲染(如果没有GPU),因此GPU和软件渲染之间的输出相当接近。

编辑:虽然这已被选为答案,但这只是一个早期尝试解释,并没有真正解决真正的原因。 读者可以参考对问题的评论和答案中的讨论。

为什么你假设他们使用相同的公式?

即使他们使用相同的公式并且您接受实现不同,您是否期望输出相同?

在一天结束时,代码被设计为使用感知而不是在数学上精确。 虽然如果你愿意,你可以通过CUDA获得这个。

如果你得到像素完美的匹配,我会非常惊讶你不会惊讶你会得到不同的结果。

他们代表颜色的方式是不同的…我知道一个事实nvidia使用浮点(可能是双)来表示GDI使用int我相信的颜色。

http://en.wikipedia.org/wiki/GPGPU

在DX9中出现着色器2.0,当执行颜色从int切换到24和32位浮点数时。

尝试将ati / amd渲染与nvidia渲染进行比较,您可以清楚地看到颜色非常不同。 我在地震2中首次注意到这一点……两张牌之间的区别是惊人的 – 当然这是由于很多东西,其中最少的是他们更加笨拙的interp实现。

编辑:我回答之后关于规范是如何发生的信息。 无论如何,我认为用于存储它的数据类型无论你如何指定它都会有所不同。 此外,浮动的实现可能是不同的。 我可能错了,但我很确定c#实现浮动不同于nvidia使用的C编译器。 (并假设GDI +只是将float转换为等效的int ….)

即使我错了,我也会认为期望2种不同的算法实现是相同的。 它们因速度而受到优化,因此光学化的差异将直接转化为图像质量的差异,因为这种速度将来​​自不同的切角/近似方法。

四舍五入的差异有两种可能性。 第一个是显而易见的,当RGB值计算为任一侧的值的一部分。 当计算在确定两点之间的分数时使用的比率时,第二种是更微妙的。

如果算法的两个不同实现是像素对像素相同,那么实际上会非常惊讶,有很多地方可以发生+/- 1的差异。 如果没有得到两种方法的确切实现细节,就不可能比这更精确。