猿问

如何找到两个图像之间的差异?

我正在开发一个屏幕共享应用程序。在这个项目中,我需要通过互联网传输图像。显然,我无法每隔几秒钟就通过互联网发送一张新照片,这将非常慢。我想将服务器屏幕的一个图像发送给客户端,然后再发送新图像,而不是发送仅发送自上一个图像(客户端已具有的图像)以来已更改的像素的新图像。


我写了这段代码:


private List<Color> CompareBitmaps(Image old, Image _new)

{

    List<Color> returnList = new List<Color>();


    for(int i = 0; i < old.Width; i++)

        for (int j = 0; j < old.Height; j++)

        {

            if (((Bitmap)old).GetPixel(i, j) != ((Bitmap)_new).GetPixel(i, j))

            {

                returnList.Add(((Bitmap)_new).GetPixel(i, j));

            }

        }


return returnList;

}

但是,它的工作速度太慢。


我正在寻找一种更快,更复杂的算法。


注意:我不想要一个能做到这一点的内置库。我需要一个算法。


拉丁的传说
浏览 666回答 3
3回答

交互式爱情

此例程查找两个位图之间的差异,并通过将其他所有内容设置为几乎黑色且几乎透明的方式在第一位图中返回它们。通过将结果添加回前一个图像,它也可以还原原始的第二个文件。我缩小了800MB 1o 12k的屏幕截图-但Clocks指针的确只有很小的变化;-)如果您的图像在许多像素上有所不同,则压缩效果将不会那么出色..但是我相信它将足够好进行传输,我怀疑以像素为单位的任何内容都可以与png或jpg文件格式的压缩例程进行比较。.(我希望您不传输bmp!)该例程使用LockBits并且非常快。bool参数决定是创建差异位图还是恢复更改后的位图。public static Bitmap Difference(Bitmap bmp0, Bitmap bmp1, bool restore){&nbsp; &nbsp; int Bpp = 4;&nbsp; // assuming an effective pixelformat of 32bpp&nbsp; &nbsp; var bmpData0 = bmp0.LockBits(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Rectangle(0, 0, bmp0.Width, bmp0.Height),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImageLockMode.ReadWrite, bmp0.PixelFormat);&nbsp; &nbsp; var bmpData1 = bmp1.LockBits(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Rectangle(0, 0, bmp1.Width, bmp1.Height),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImageLockMode.ReadOnly, bmp1.PixelFormat);&nbsp; &nbsp; int len = bmpData0.Height * bmpData0.Stride;&nbsp; &nbsp; byte[] data0 = new byte[len];&nbsp; &nbsp; byte[] data1 = new byte[len];&nbsp; &nbsp; Marshal.Copy(bmpData0.Scan0, data0, 0, len);&nbsp; &nbsp; Marshal.Copy(bmpData1.Scan0, data1, 0, len);&nbsp; &nbsp; for (int i = 0; i < len; i += Bpp)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (restore)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bool toberestored = (data1[i&nbsp; ] != 2 && data1[i+1] != 3 &&&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;data1[i+2] != 7 && data1[i+2] != 42);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (toberestored)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i&nbsp; ] = data1[i];&nbsp; &nbsp; // Blue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+1] = data1[i+1];&nbsp; // Green&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+2] = data1[i+2];&nbsp; // Red&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+3] = data1[i+3];&nbsp; // Alpha&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bool changed = ((data0[i&nbsp; ] != data1[i&nbsp; ]) ||&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (data0[i+1] != data1[i+1]) || (data0[i+2] != data1[i+2]) );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i&nbsp; ] = changed ? data1[i&nbsp; ] : (byte)2;&nbsp; &nbsp;// special markers&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+1] = changed ? data1[i+1] : (byte)3;&nbsp; &nbsp;// special markers&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+2] = changed ? data1[i+2] : (byte)7;&nbsp; &nbsp;// special markers&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data0[i+3] = changed ? (byte)255&nbsp; : (byte)42;&nbsp; // special markers&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; Marshal.Copy(data0, 0, bmpData0.Scan0, len);&nbsp; &nbsp; bmp0.UnlockBits(bmpData0);&nbsp; &nbsp; bmp1.UnlockBits(bmpData1);&nbsp; &nbsp; return bmp0;}注意:-我选择了一种特殊的颜色来标记那些需要在接收者处恢复的像素。在这里,我选择了alpha=42和R=7; G=3; B=2;... ...而不是100%安全的,但几乎; 不会错过很多像素;也许您仍然没有透明度..?

子衿沉夜

您需要返回所有更改的像素,因此复杂度必须为m * n。(Bitmap)_new).GetPixel(i,j)被调用了两次,使用临时值存储它可能会更好一些。像素应该有几个值吧?您可以尝试创建一个名为comprareTwoPixel(color A,color B)的函数吗?并一一比较所有值,如果其中之一为假,则无需比较其余值,只需返回false。(不知道这样做是否会更快。)喜欢:bool comprareTwoPixel(color A, color B){&nbsp; &nbsp; if(A.a!=B.b)&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; if(A.b!=B.b)&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; if(A.c!=B.c)&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; return true;}
随时随地看视频慕课网APP
我要回答