为什么位图比较不等于自身? [英] Why does a bitmap compare not equal to itself?

查看:131
本文介绍了为什么位图比较不等于自身?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这有点令人困惑.以下代码是一个小的测试应用程序的一部分,该应用程序用于验证代码更改没有引入回归.为了使其变得更快,我们使用了memcmp,它似乎是比较两个相同大小图像的最快方法(毫不奇怪)

This is a bit puzzling here. The following code is part of a little testing application to verify that code changes didn't introduce a regression. To make it fast we used memcmp which appears to be the fastest way of comparing two images of equal size (unsurprisingly).

但是,我们有一些测试图像表现出一个相当令人惊讶的问题:位图数据上的memcmp告诉我们它们不相等,但是,逐像素比较根本没有发现任何区别.我的印象是,在Bitmap上使用LockBits时,您会得到图像的实际原始字节.对于24 bpp位图,很难想象像素相同但基础像素 data 不相同的情况.

However, we have a few test images that exhibit a rather surprising problem: memcmp on the bitmap data tells us that they are not equal, however, a pixel-by-pixel comparison doesn't find any difference at all. I was under the impression that when using LockBits on a Bitmap you get the actual raw bytes of the image. For a 24 bpp bitmap it's a bit hard to imagine a condition where the pixels are the same but the underlying pixel data isn't.

一些令人惊讶的事情:

  1. 差异总是 个单字节,在一个图像中是00,在另一图像中是FF.
  2. 如果将LockBitsPixelFormat更改为Format32bppRgbFormat32bppArgb,则比较成功.
  3. 如果将第一个LockBits调用返回的BitmapData作为第四个参数传递给第二个,则比较成功.
  4. 如上所述,逐像素比较也成功.
  1. The differences are always single bytes that are 00 in one image and FF in the other.
  2. If one changes the PixelFormat for LockBits to Format32bppRgb or Format32bppArgb, the comparison succeeds.
  3. If one passes the BitmapData returned by the first LockBits call as 4th argument to the second one, the comparison succeeds.
  4. As noted above, the pixel-by-pixel comparison succeeds as well.

我在这里有些困惑,因为坦率地说我无法想象为什么发生这种情况.

I'm a bit stumped here because frankly I cannot imagine why this happens.

(精简版)下面的代码.只需使用csc /unsafe进行编译,并将24bpp PNG图像作为第一个参数传递.

(Reduced) Code below. Just compile with csc /unsafe and pass a 24bpp PNG image as first argument.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

class Program
{
    public static void Main(string[] args)
    {
        Bitmap title = new Bitmap(args[0]);
        Console.WriteLine(CompareImageResult(title, new Bitmap(title)));
    }

    private static string CompareImageResult(Bitmap bmp, Bitmap expected)
    {
        string retval = "";

        unsafe
        {
            var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            var resultData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
            var expectedData = expected.LockBits(rect, ImageLockMode.ReadOnly, expected.PixelFormat);

            try
            {
                if (memcmp(resultData.Scan0, expectedData.Scan0, resultData.Stride * resultData.Height) != 0)
                    retval += "Bitmap data did not match\n";
            }
            finally
            {
                bmp.UnlockBits(resultData);
                expected.UnlockBits(expectedData);
            }
        }

        for (var x = 0; x < bmp.Width; x++)
            for (var y = 0; y < bmp.Height; y++)
                if (bmp.GetPixel(x, y) != expected.GetPixel(x, y))
                {
                    Console.WriteLine("Pixel diff at {0}, {1}: {2} - {3}", x, y, bmp.GetPixel(x, y), expected.GetPixel(x, y));
                    retval += "pixel fail";
                }

        return retval != "" ? retval : "success";
    }

    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int memcmp(IntPtr b1, IntPtr b2, long count);
}

推荐答案

看一看,该图以图形方式说明了一个LockBits缓冲区-它显示了步幅行,以及填充可以出现在步幅末尾(如果是的话)需要).

Take a look at this, which pictorially illustrates a LockBits buffer - it shows the Rows of Strides and where Padding can appear at the end of the Stride (if it's needed).

  • http://supercomputingblog.com/graphics/using-lockbits- in-gdi/

    一个跨度可能会与32位(即单词)边界对齐(出于效率目的)...并且跨度结尾处多余的未使用空间将使下一个跨度对齐.

    A stride is probably aligned to the 32bit (i.e. word) boundary (for efficiency purposes)...and the extra unused space at the end of the stride is to make the next Stride be aligned.

    这就是在比较期间为您提供随机行为的原因...填充区域中的虚假数据.

    So that's what's giving you the random behaviour during the comparison...spurious data in the Padding region.

    当您使用Format32bppRgb和Format32bppArgb时,它们自然是字对齐的,因此我想您最后没有多余的未使用位,这就是它起作用的原因.

    When you are using Format32bppRgb and Format32bppArgb that's naturally word aligned, so I guess you don't have any extra unused bits on the end, which is why it works.

    这篇关于为什么位图比较不等于自身?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆