为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
拉丁的传说 2019-12-05 15:47:35
我正在开发一个屏幕共享应用程序。在这个项目中,我需要通过互联网传输图像。显然,我无法每隔几秒钟就通过互联网发送一张新照片,这将非常慢。我想将服务器屏幕的一个图像发送给客户端,然后再发送新图像,而不是发送仅发送自上一个图像(客户端已具有的图像)以来已更改的像素的新图像。我写了这段代码: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;}但是,它的工作速度太慢。我正在寻找一种更快,更复杂的算法。注意:我不想要一个能做到这一点的内置库。我需要一个算法。
查看完整描述

3 回答

?
交互式爱情

TA贡献1712条经验 获得超3个赞

此例程查找两个位图之间的差异,并通过将其他所有内容设置为几乎黑色且几乎透明的方式在第一位图中返回它们。通过将结果添加回前一个图像,它也可以还原原始的第二个文件。


我缩小了800MB 1o 12k的屏幕截图-但Clocks指针的确只有很小的变化;-)如果您的图像在许多像素上有所不同,则压缩效果将不会那么出色..但是我相信它将足够好进行传输,我怀疑以像素为单位的任何内容都可以与png或jpg文件格式的压缩例程进行比较。.(我希望您不传输bmp!)


该例程使用LockBits并且非常快。


bool参数决定是创建差异位图还是恢复更改后的位图。


public static Bitmap Difference(Bitmap bmp0, Bitmap bmp1, bool restore)

{

    int Bpp = 4;  // assuming an effective pixelformat of 32bpp

    var bmpData0 = bmp0.LockBits(

                    new Rectangle(0, 0, bmp0.Width, bmp0.Height),

                    ImageLockMode.ReadWrite, bmp0.PixelFormat);

    var bmpData1 = bmp1.LockBits(

                    new Rectangle(0, 0, bmp1.Width, bmp1.Height),

                    ImageLockMode.ReadOnly, bmp1.PixelFormat);


    int len = bmpData0.Height * bmpData0.Stride;

    byte[] data0 = new byte[len];

    byte[] data1 = new byte[len];

    Marshal.Copy(bmpData0.Scan0, data0, 0, len);

    Marshal.Copy(bmpData1.Scan0, data1, 0, len);


    for (int i = 0; i < len; i += Bpp)

    {

        if (restore)

        {

            bool toberestored = (data1[i  ] != 2 && data1[i+1] != 3 && 

                                 data1[i+2] != 7 && data1[i+2] != 42);

            if (toberestored)

            {

                data0[i  ] = data1[i];    // Blue

                data0[i+1] = data1[i+1];  // Green 

                data0[i+2] = data1[i+2];  // Red

                data0[i+3] = data1[i+3];  // Alpha

            }

        }

        else

        {

            bool changed = ((data0[i  ] != data1[i  ]) ||  

                            (data0[i+1] != data1[i+1]) || (data0[i+2] != data1[i+2]) );

            data0[i  ] = changed ? data1[i  ] : (byte)2;   // special markers

            data0[i+1] = changed ? data1[i+1] : (byte)3;   // special markers

            data0[i+2] = changed ? data1[i+2] : (byte)7;   // special markers

            data0[i+3] = changed ? (byte)255  : (byte)42;  // special markers

        }

    }


    Marshal.Copy(data0, 0, bmpData0.Scan0, len);

    bmp0.UnlockBits(bmpData0);

    bmp1.UnlockBits(bmpData1);

    return bmp0;

}

注意:-我选择了一种特殊的颜色来标记那些需要在接收者处恢复的像素。在这里,我选择了alpha=42和R=7; G=3; B=2;... ...而不是100%安全的,但几乎; 不会错过很多像素;也许您仍然没有透明度..?


查看完整回答
反对 回复 2019-12-05
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

您需要返回所有更改的像素,因此复杂度必须为m * n。


(Bitmap)_new).GetPixel(i,j)被调用了两次,使用临时值存储它可能会更好一些。


像素应该有几个值吧?您可以尝试创建一个名为comprareTwoPixel(color A,color B)的函数吗?并一一比较所有值,如果其中之一为假,则无需比较其余值,只需返回false。(不知道这样做是否会更快。)


喜欢:


bool comprareTwoPixel(color A, color B)

{

    if(A.a!=B.b)

        return false;

    if(A.b!=B.b)

        return false;

    if(A.c!=B.c)

        return false;


    return true;

}


查看完整回答
反对 回复 2019-12-05
  • 3 回答
  • 0 关注
  • 665 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信