嘿那里!
这是我的设置:
我有一个c#应用程序,它从一系列图像中提取特征。由于数据集的大小(数千个图像),它被大量并行化,这就是为什么我们拥有一台运行在Windows7 x64(.NET4运行时)上的ssd的高端机器,以解除繁重的工作。我在带有Windows窗体的Visual Studio 2008(.NET3.5)下的Windows XP SP3 x86机器上开发它 - 顺便说一句,没有机会转向WPF。
EDIT3: 这很奇怪,但我想我终于找到了正在发生的事情。似乎是图像格式的编解码器,在两台机器上产生不同的结果!我不确切知道那里发生了什么,但xp机器上的解码器产生比win7更健全的结果。遗憾的是更好的版本仍然在x86 XP系统中:(。我想这个问题的唯一解决方案是将输入图像格式改为像png或bmp一样无损的东西(愚蠢的我不考虑文件格式首先:))。
EDIT2: 感谢你付出的努力。我想我会坚持自己实现一个转换器,它不是我想要的,但我必须以某种方式解决它:)。如果有人正在阅读这个有我想法的人,请告诉我。
修改
在评论中,我建议使用第三方库。我认为我并没有让自己清楚,因为我并不是真的想要使用DrawImage方法 - 它只是一个有缺陷的快速方法来获得实际工作new Bitmap(tmp, ... myPixelFormat)
希望使用一些插值。我想要实现的仅仅是通过一些标准插值将输入图像转换为普通的PixelFormat。
我的问题如下。一些源图像采用 Indexed8bpp jpg 格式,与WinForms成像内容不能很好地相处。因此,在我的图像加载逻辑中,检查索引图像,将图像转换为我的应用程序默认格式(例如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;
}
我将问题追溯到(*)
。我认为InterpolationMode与它有关,但是我选择的哪一个结果在两个系统的(**)
上都是不同的。我一直在用一些愚蠢的复制和粘贴行调查测试图像数据,以确保它不会以错误的方式访问数据。
所有图像都像Electron Backscatter Diffraction Pattern一样。实际的颜色值略有不同,但它们带有大量信息 - 插值甚至可以增强它。看起来x86机器上的合成算法使用InterpolationMode属性,而x64 thingy只是将调色板值扩展出来而不考虑任何插值。
直到我在应用程序中的数据上实现直方图视图功能的那一天,我才注意到两台机器的输出之间没有任何区别。在x86机器上,它是平衡的,因为人们期望它能够观看图像。另一方面,x64机器宁愿提供某种稀疏条形图,这是索引图像数据的指示。它甚至会影响整个应用程序的整体输出数据 - 两台机器上的输出在数据相同时都不同,这不是一件好事。
对我而言,它看起来像x64实现中的一个错误,但那只是我:-)。我只是希望x64机器上的图像具有与x86相同的值。
如果有人有想法,我会非常高兴。我已经在网上寻找类似的行为多年,但阻力似乎是徒劳的:)
哦,请注意......鲸鱼!
答案 0 :(得分:1)
如果您想确保始终以相同的方式完成此操作,则必须编写自己的代码来处理它。幸运的是,这并不太难。
您的8bpp图像有一个包含实际颜色值的调色板。您需要读取该调色板并将颜色值(如果我没记错,是24位)转换为16位颜色值。您将在转换中丢失信息,但您的转化信息已经丢失。至少这样,你会以可预测的方式丢失信息。
将转换后的颜色值(不会超过256个)放入可用于查找的数组中。然后......
创建目标位图并调用LockBits
以获取指向实际位图数据的指针。调用LockBits
以获取指向源位图的位图数据的指针。然后,对于每个像素:
read the source bitmap pixel (8 bytes)
get the color value (16 bits) from your converted color array
store the color value in the destination bitmap
您可以使用GetPixel
和SetPixel
执行此操作,但速度非常慢。
答案 1 :(得分:1)
我模糊地回想起.NET图形类依赖于GDI +。如果今天仍然如此,那么在使用不同视频驱动程序的不同64位系统上尝试您的应用程序毫无意义。您最好的选择是使用原始GDI操作(P / Invoke)进行插值,或者在软件中编写自己的像素插值例程。这两种选择都不是特别有吸引力。
答案 2 :(得分:0)
你真的应该使用OpenCV进行图像处理,它可以在C#中找到:OpenCVSharp。
答案 3 :(得分:0)
我对图形对象使用标准方法,并且此设置的性能优于X86。在发布运行时计算性能,而不是调试。还要在项目属性的“构建”选项卡上检查优化代码。 Studio 2017,框架4.7.1
public static Graphics CreateGraphics(Image i)
{
Graphics g = Graphics.FromImage(i);
g.CompositingMode = CompositingMode.SourceOver;
g.CompositingQuality = CompositingQuality.HighSpeed;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.SmoothingMode = SmoothingMode.HighSpeed;
return g;
}