嘿!Graphics.DrawImage在x86和x64上創建不同的圖像數據
這裏是我的設置:
我已經得到了來自一系列圖像中提取特徵的C#應用程序。由於數據集的大小(數千個圖像),它大量並行化,這就是爲什麼我們有一臺運行在Windows7 x64(.NET4運行時)上的ssd的高端機器來解除艱苦的工作。我正在使用Windows Forms在Visual Studio 2008(.NET3.5)下的Windows XP SP3 x86計算機上開發它 - 順便提一下,沒有機會轉移到WPF。
編輯3: 這很奇怪,但我想我終於知道發生了什麼事情。似乎是在兩臺機器上產生不同結果的圖像格式的編解碼器!我不知道到底發生了什麼,但是xp機器上的解碼器產生比win7更好的結果。可悲的是更好版本仍然在x86 XP系統:(我想這個唯一的解決方案是將輸入圖像格式更改爲無損像png或bmp(愚蠢的我沒有考慮文件格式的第一位:))。
編輯2: 謝謝你的努力。我想我會堅持自己實現一個轉換器,這不是我想要的,但我必須以某種方式解決它:)。如果有人正在閱讀對我有一些想法的人,請告訴我。
編輯: 在評論中,我被建議使用第三方庫爲此。我想我沒有把自己弄清楚,因爲我真的不想使用DrawImage方法 - 這只是一個有缺陷的快速獲得實際工作的new Bitmap(tmp, ... myPixelFormat)
,希望使用一些插值。我想實現的目的僅僅是將輸入的圖像轉換爲具有一些標準插值的普通PixelFormat。
我的問題如下。某些源圖像格式與WinForms映像文件不兼容,格式爲Indexed8bpp jpg。因此,在我的圖像加載邏輯沒有用於將圖像轉換爲我的應用程序默認的格式(例如Format16bpp)這樣的索引圖像進行檢查:
Image GetImageByPath(string path)
{
Image result = null;
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Image tmp = Image.FromStream(fs); // Here goes the same image ...
if (tmp.PixelFormat == PixelFormat.Format1bppIndexed ||
tmp.PixelFormat == PixelFormat.Format4bppIndexed ||
tmp.PixelFormat == PixelFormat.Format8bppIndexed ||
tmp.PixelFormat == PixelFormat.Indexed)
{
// Creating a Bitmap container in the application's default format
result = new Bitmap(tmp.Width, tmp.Height, DefConf.DefaultPixelFormat);
Graphics g = Graphics.FromImage(result);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// We need not to scale anything in here
Rectangle drawRect = new Rectangle(0, 0, tmp.Width, tmp.Height);
// (*) Here is where the strange thing happens - I know I could use
// DrawImageUnscaled - that isn't working either
g.DrawImage(tmp, drawRect, drawRect, GraphicsUnit.Pixel);
g.Dispose();
}
else
{
result = new Bitmap(tmp); // Just copying the input stream
}
tmp.Dispose();
}
// (**) At this stage the x86 XP memory image differs from the
// the x64 Win7 image despite having the same settings
// on the very same image o.O
result.GetPixel(0, 0).B; // x86: 102, x64: 102
result.GetPixel(1, 0).B; // x86: 104, x64: 102
result.GetPixel(2, 0).B; // x86: 83, x64: 85
result.GetPixel(3, 0).B; // x86: 117, x64: 121
...
return result;
}
我跟蹤這個問題到(*)
。我認爲插值模式與它有關,但無論如何,我選擇的結果在(**)
上都不相同。我一直在用一些愚蠢的副本&粘貼線來調查測試圖像數據,以確保它不是以錯誤的方式訪問數據的問題。
圖像都在一起看起來像這樣Electron Backscatter Diffraction Pattern。實際的顏色值有細微的差別,但它們帶有大量的信息 - 插值甚至可以增強它。它看起來像x86機器上的組合算法使用InterpolationMode屬性,而x64只是將調色板值分散出去,而沒有考慮任何插值。
我從來沒有注意到兩臺機器的輸出之間有任何差異,直到我對應用程序中的數據實現直方圖視圖功能爲止。在x86機器上,它是平衡的,正如人們期望它可以觀看圖像一樣。另一方面,x64機器寧願給出某種稀疏的條形圖,這是索引圖像數據的指示。它甚至會影響整個應用程序的整體輸出數據 - 兩臺機器上的輸出數據相同,但這不是一件好事。
對我來說,它看起來像在x64實現中的錯誤,但這只是我:-)。我只想讓x64機器上的圖像具有與x86相同的值。
如果有人有一個想法,我會很高興。我一直在尋找類似的行爲在網絡上的年齡,但抵抗似乎徒勞:)
哦,看看......鯨魚!
是的,Graphics.DrawImage()需要一些快捷方式,導致像素顏色值的細微變化。太小而不能被人眼察覺。 64位算法將稍微有點不同。處理這個問題的一種可能的方法是聲明x86版本是錯誤的:) –
哇,這是快速的...我明白你的觀點,但它不能解決我的問題,因爲它是x86版本,可以產生「更好」結果:) – mfeineis
我不會建議依賴Graphics DrawImage方法的數字穩定性,因爲它的目的是顯示圖像,而不是保存信息。例如,它的實現有可能在未來發生變化。 –