【问题标题】:How to compare 2 images and compare them如何比较2张图片并进行比较
【发布时间】:2022-12-15 01:05:28
【问题描述】:

我正在制作一个录像机,该应用程序通过拍摄大量屏幕截图并将它们放在一个视频中来工作。另外,我正在尝试制作诸如屏幕运动检测之类的东西。仅当检测到屏幕差异时,我才需要该应用程序截取屏幕截图。我在考虑如何做到这一点,我相信我需要让它在与之前的比较时仍然截取屏幕截图。有没有办法做到这一点?

编码:

        //Record video:
        public void RecordVideo()
        {
            //Keep track of time:
            watch.Start();

            using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    //Add screen to bitmap:
                    g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
                }
                //Save screenshot:

                string name = tempPath + "//screenshot-" + fileCount + ".png";
                bitmap.Save(name, ImageFormat.Png);
                inputImageSequence.Add(name);
                fileCount++;

                //Dispose of bitmap:
                bitmap.Dispose();
            }
        }

【问题讨论】:

    标签: c#


    【解决方案1】:

    我有一些可能对你有用的东西。这个想法是只保存图像之间的差异,然后根据起始图像和保存的更改重新创建所有图像。

    为此,您只需要对图像字节进行异或运算。此方法允许您获得两个图像之间的差异(array 参数):

    protected void ApplyXor(Bitmap img1, Bitmap img2, byte[] array)
    {
        const ImageLockMode rw = ImageLockMode.ReadWrite;
        const PixelFormat argb = PixelFormat.Format32bppArgb;
    
        var locked1 = img1.LockBits(new Rectangle(0, 0, img1.Width, img1.Height), rw, argb);
        var locked2 = img2.LockBits(new Rectangle(0, 0, img2.Width, img2.Height), rw, argb);
    
        try
        {
            ApplyXor(locked2, locked1, array);
        }
        finally
        {
            img1.UnlockBits(locked1);
            img2.UnlockBits(locked2);
        }
    }
    

    有了前面的img1位图和返回的array,你可以用这个方法得到img2

    protected void ApplyXor(Bitmap img1, byte[] array, Bitmap img2)
    {
        const ImageLockMode rw = ImageLockMode.ReadWrite;
        const PixelFormat argb = PixelFormat.Format32bppArgb;
    
        var locked1 = img1.LockBits(new Rectangle(0, 0, img1.Width, img1.Height), rw, argb);
        var locked2 = img2.LockBits(new Rectangle(0, 0, img2.Width, img2.Height), rw, argb);
    
        try
        {
            ApplyXor(locked1, array, locked2);
        }
        finally
        {
            img1.UnlockBits(locked1);
            img2.UnlockBits(locked2);
        }
    }
    

    这里是其他所需的方法:

    private unsafe void ApplyXor(BitmapData img1, BitmapData img2, byte[] array)
    {
        byte* prev0 = (byte*)img1.Scan0.ToPointer();
        byte* cur0 = (byte*)img2.Scan0.ToPointer();
    
        int height = img1.Height;
        int width = img1.Width;
        int halfwidth = width / 2;
    
        fixed (byte* target = array)
        {
            ulong* dst = (ulong*)target;
    
            for (int y = 0; y < height; ++y)
            {
                ulong* prevRow = (ulong*)(prev0 + img1.Stride * y);
                ulong* curRow = (ulong*)(cur0 + img2.Stride * y);
    
                for (int x = 0; x < halfwidth; ++x)
                {
                    if (curRow[x] != prevRow[x])
                    {
                        int a = 0;
                    }
    
                    *(dst++) = curRow[x] ^ prevRow[x];
                }
            }
        }
    }
    
    private unsafe void ApplyXor(BitmapData img1, byte[] array, BitmapData img2)
    {
        byte* prev0 = (byte*)img1.Scan0.ToPointer();
        byte* cur0 = (byte*)img2.Scan0.ToPointer();
    
        int height = img1.Height;
        int width = img1.Width;
        int halfwidth = width / 2;
    
        fixed (byte* target = array)
        {
            ulong* dst = (ulong*)target;
    
            for (int y = 0; y < height; ++y)
            {
                ulong* prevRow = (ulong*)(prev0 + img1.Stride * y);
                ulong* curRow = (ulong*)(cur0 + img2.Stride * y);
    
                for (int x = 0; x < halfwidth; ++x)
                {
                    curRow[x] = *(dst++) ^ prevRow[x];
                }
            }
        }
    }
    

    注意:您必须将项目配置为允许不安全。

    使用以前的方法,您可以执行以下操作:

    • 保存 img1 位图
    • 获取img2位图,异或得到数组(例如array2)
    • 对于 img3,获取与 img2(例如数组 3)的 XOR。现在,不需要 img2
    • 对于 img4,获取与 img3 (array4) 的 XOR。现在,不需要 img3
    • ...

    您有 img1 和 array2、array3、array4...,您可以重新创建所有图像:

    • img1 和 array2 异或得到 img2
    • img2 和 array3 异或得到 img3
    • ...

    如果您需要通过 TCP 发送视频,您可以发送图像发送一个图像和 XOR 数组(差异)。或者更好的是,使用 K4os.Compression.LZ4 压缩 XOR 数组。

    【讨论】:

    • 但这实际上是如何检测到变化的呢?
    • @DiplomacyNotWar xor 给你改变。如果数组包含任何 1 值,则图像发生变化。该代码很有趣,因为相似的图像为您提供了一个包含大量 0 的数组,您可以对其进行大量压缩并通过套接字发送很少的信息。我的回答可能不是很清楚,但关键在于使用 xor 数组获得的压缩因子
    • OP 有一个摄像头,他们只想在场景中有运动时录制视频。当然,XOR 可以帮助您减少需要发送的信息,但即使是日出到日落的缓慢过渡也会导致相机图像发生变化。你如何区分它与使用 XOR 的运动?
    • @DiplomacyNotWar 我的回答不适用于这种情况。我认为最好的选择是使用这个答案 stackoverflow.com/a/17626650/18452174 中的库 (DRY)。
    • 在 RecordVideo 中,您可以使用以前的图像和新图像并进行 XOR 以获得具有差异的数组(数组中的 1 是差异)。您可以获得数组中 1 的百分比,如果低于某个阈值,则认为它没有变化。但是,例如,光照的变化会给你不同的图像。这不是检查图像是否发生变化的最佳方法。我在一个应用程序(如远程桌面)中使用它来通过 TCP 发送图像差异。这是一个不同的问题。我推荐你使用一些运动检测库。
    猜你喜欢
    • 2011-03-17
    • 1970-01-01
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 2014-01-24
    相关资源
    最近更新 更多