【问题标题】:Get most similar image [duplicate]获取最相似的图像[重复]
【发布时间】:2017-11-08 17:55:43
【问题描述】:

我有一个 Bitmap A 和一个 Bitmap 数组,在数组中有一个 Bitmap 看起来和 Bitmap A 一样。我正在使用下面的代码,但它有时不起作用,它迭代整个数组而没有找到它,似乎有一些细微的差别,如果函数 90% 相似或选择数组中最相似的图像,有没有办法将函数更改为返回 true?该数组只有 6 张图像。

 for(int i = 0; i < list.Count;i++)
    {
        if(ImageCompareString(image,list[i])
        {
            answerIndex = i;
            break;
        }
    }

private static bool ImageCompareString(Bitmap firstImage, Bitmap secondImage)
{
    MemoryStream ms = new MemoryStream();
    firstImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
    String firstBitmap = Convert.ToBase64String(ms.ToArray());
    ms.Position = 0;

    secondImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
    String secondBitmap = Convert.ToBase64String(ms.ToArray());

    if (firstBitmap.Equals(secondBitmap))
    {
        return true;
    }
    else
    {
        return false;
    }
}

【问题讨论】:

    标签: c# bitmap image-comparison


    【解决方案1】:

    当然有这样的方式……但你必须自己编码。

    首先您不应该比较 base64 数据...您将失去直接像素值访问权限并将要比较的数据大小增加 150% 以上(最初为 200%,但已更正谢谢到 PeterDuniho 的评论)由于 UTF16 在 C# 中。
    第二我假设所有图片都具有相同的固定大小。在比较之前,将图像尺寸减小到非常小的尺寸,但保持宽度/高度方面。这将加快比较速度并消除噪点。
    第三迭代两张图片并比较它们的灰度像素值。我假设您已将图片大小调整为 16x16。由于我们正在比较它们的灰度值,因此一个像素的 介于 0 和 255 之间。因此,两张图片之间的最大距离将为 16 * 16 * 256 = 65536。如果两张图片都是黑色的,则图片之间的距离将为零(100% 相似度)。如果一张图片是黑色而另一张图片是白色,则距离将为 65535(0% 相似度)。

    要比较图像,迭代图片像素并在点grayscale-pixel-value-of-picture-b 中减去grayscale-pixel-value-from-picture-a x,y 并将绝对 差值添加到计数器。这个计数器将是两张图片之间的总距离。 让我们假设这个计数器在比较循环之后的值为 1000,您可以通过1000 / 65535 获得两张图片之间的百分比相似度 ~ 1.5% 的差异(或 98.5% 的相似度)。

    伪比较代码

    long counter = 0;
    long total = image.Width * image.Height * (Color.White - Color.Black);
    for(int x = 0; x < image.Width; x++)
    {
        for(int y = 0; y < image.Height; y++)
        {
            var p1 = image.GetPixel(x, y);
            var p2 = otherImage.GetPixel(x, y);
            var g1 = ((p1.R + p1.G + p1.B) / 3);
            var g2 = ((p2.R + p2.G + p2.B) / 3);
            var distance = Math.Abs(g1 - g2);
            counter += distance;
        }
    }
    var similarity = 100 - ((counter / total) * 100);
    

    这是一种或多或少简单的方法,但您必须使用您的场景/图像进行测试。除了比较灰度值,您还可以比较 rgb 值。寻找像欧几里得距离这样的距离定义......开始并继续阅读:)

    编辑
    这只是一个非常基本的方法,应该解释如何开始比较图像。它没有考虑可能存在不同的图像格式(jpeg、png、gif)、颜色格式(索引、16bit、24bit、32bit)或不同分辨率的图像。

    【讨论】:

    • 转换为 base64 不会“丢失 [原文如此]”像素值。他们只是得到不同的代表。首先转换为 PNG 会阻止有效的比较。 base64 的数据大小增加“仅”33%。即使考虑到二进制中的 6 位转换为 16 位(因为 C# 字符串是 UTF16)这一事实,这“仅”增加了 167%,而不是“超过 [原文如此] 200%”。虽然减小图像尺寸可以提高速度,但它确实会丢失像素信息,转换为灰度也会丢失。考虑例如将纯色图像与其他纯色图像进行比较。
    • @PeterDuniho 你是对的,像素值的表示方式不同 - 但这使得访问点 x,y 的像素值变得更加困难,我(个人)只看到 base64 转换中的缺点.通过向下和灰度化丢失的像素信息是正确的(并且可能需要),并且对于大多数情况来说 16x16 肯定很小,但更容易解释如何开始比较图像和获得第一个结果的步骤。有了第一个结果,他可以开始调整参数,如大小或 rgb/灰度或使用的距离......
    猜你喜欢
    • 2012-08-25
    • 2011-04-16
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    相关资源
    最近更新 更多