【发布时间】:2015-03-03 01:17:53
【问题描述】:
我正在开发一个定期保存打印屏幕的应用程序,比如 10 秒。
一般来说,图像非常相似,有时是相等的,所以我想创建一个位图来表示当前打印屏幕和前一个打印屏幕之间的差异。
为了实现这一点,我逐像素比较了 2 个图像,当它们相等时,我将像素设置为透明颜色(在原始代码中,我使用 Bitmap.LockBits 以获得更好的性能) :
for (var x = 0; x < width; y++)
for (var y = 0; y < height; y++)
{
var oldColor = lastPrint.GetPixel(x, y);
var color = currentPrint.GetPixel(x, y);
if (oldColor == color)
{
differencePrint.SetPixel(x, y, Color.Transparent);
}
}
为了恢复图像,我得到第一个打印屏幕并替换为顺序位图。
private void MergePrints()
{
var lastBitmap = new BitMap(firstPrint);
foreach (var print in prints.OrderBy(e => e.Date))
{
using (var difference = new Bitmap(print.Image))
{
using (var grfx = Graphics.FromImage(lastBitmap))
{
grfx.DrawImage(difference, 0, 0);
}
}
lastBitmap.Save(print.id + ".png");
}
lastBitmap.Dispose();
}
我的问题是:除了具有透明像素的新图像之外,是否有更好的方法来生成表示两个图像之间差异的对象?也许是一个新的班级?但是这个类需要持久化,当然比位图“更小”,目前我在使用 7zip 算法压缩它后将位图持久化为 byte[]。
【问题讨论】:
-
您是否只是要求一个能够容纳您的差异的数据访问对象?在这种情况下,它只是
System.Drawing.Point的列表,即您只需要存储公共区域的 x,y,这似乎就是您所需要的 - 您已经具备根据该信息创建新图像的功能。 -
是的,但是我需要一个不常见像素的列表,而不是一个常见像素的列表,它就像一个代表差异的 Dictionary
。但是,如果我采用这种方法,我还需要保留字典,将它保留在这本字典中的最佳方法是什么?每行代表一个像素的子表? -
目前您仍在使用位图,它是像素颜色数组。如果变化不大(意味着会有很多透明像素),那么只存储坐标列表(
x,y)和相应的新颜色会更有效。类似于List<Tuple<int, int, Color>>。绘制旧位图,然后从此类列表中更新点将为您提供新位图。其他选择是使用专门的容器来处理这些事情:GIF应该这样做,如果您接受图像丢失,那么MPEG等。他们使用相同的关键帧和更改的想法。 -
@Sinatr 对不起,我的无知,您认为将这些元组存储在数据库中的每个像素的行中比将透明位图数组(大小)存储在单行中更好吗?那是因为位图数组是可以使用的位图。是的,图像丢失是可以接受的
-
颜色为
4字节。坐标是,2-4(byte-uint)。如果您有50%的透明像素,则新方法会更好(25%保存,如果byte)或相同(0保存)。更重要的是——绝对是一场胜利。可以说,使用透明像素对位图进行简单压缩可能会消除更多。但是您可以进一步优化提供的方式,例如,不要保存所有点的坐标,而是保存路径(第一个点仍然是x,y,但下一个点是偏移量的byte,如果下一个点不可达,开始一条新路径)...
标签: c# image performance bitmap system.drawing