我正在使用MinHash算法在图像之间查找类似的图像。
我遇到过这篇文章How can I recognize slightly modified images?
,它指出了MinHash算法。
我在这篇博文Set Similarity and Min Hash
中使用了C#实现。
但是在尝试使用该实现时,我遇到了两个问题。
universe
值设置为什么值?HashSet
时,它只包含不同的字节值;从而比较1~256的值。 MinHash中的universe
是什么?
我该怎么做才能改进C#MinHash实现?
由于HashSet<byte>
包含的值高达256,因此相似度值总是为1。
以下是使用Set Similarity and Min Hash
的C#MinHash实现的来源:
class Program
{
static void Main(string[] args)
{
var imageSet1 = GetImageByte(@".\Images\01.JPG");
var imageSet2 = GetImageByte(@".\Images\02.TIF");
//var app = new MinHash(256);
var app = new MinHash(Math.Min(imageSet1.Count, imageSet2.Count));
double imageSimilarity = app.Similarity(imageSet1, imageSet2);
Console.WriteLine("similarity = {0}", imageSimilarity);
}
private static HashSet<byte> GetImageByte(string imagePath)
{
using (var fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(fs))
{
//List<int> bytes = br.ReadBytes((int)fs.Length).Cast<int>().ToList();
var bytes = new List<byte>(br.ReadBytes((int) fs.Length).ToArray());
return new HashSet<byte>(bytes);
}
}
}
答案 0 :(得分:11)
首先提出第二个问题:
我该怎么做才能改进C#MinHash的实现?
您正在尝试比较byte
级别的图片,以确定结构本身非常不同的文件(您将TIFF用作一个图像,将GIF用于另一个图像)。即使在视觉上这些文件完全相同,您的实现也永远不会找到重复项,除非文件属于同一类型。
也就是说,您的minhash实施应该依赖于您为了创建签名而散列的图像的可比属性。
虽然字节的值绝对是图像的属性,但如果它们的格式不同,则无法相互比较。
对于图像,您可以使用图像中每个像素的RGB(以及可能的alpha)值。无论图像的格式如何,这些值都是可比较的(您可以使用CMYK或您想要的任何其他color space)。
但是,使用每个像素的各个值会导致效果不佳。 Jaccard similarity用于比较每个集合中的值(无论是否散列任何内容),因为集合没有分配任何顺序,具有相同颜色的相同像素数的图像但安排在不同的空间会导致误报。
以下图片为例:
它们都是100px x 100px,50像素的红色和50像素的绿色。
使用Jaccard相似性来比较两者,你得到以下内容(请注意,由于值相同,每个颜色只包含一个元素。如果需要,可以使用Jaccard bag comparison比较具有相同项目的多个计数的行李,但在这种情况下,该值将变为相同):
Legend:
g = green
r = red
left image = { r, g }
right image = { r, g }
similarity = intersection(left, right) / union(left, right)
similarity = 1 / 1 = 100%
关于right image = { r, g }
的表示的说明:因为集合是无序的,{ r, g }
与{ g, r }
相同,所以它们生效,即使没有计算Jaccard比较也是如此,这一点很明显。
但显然,这些图像并不相同。
这就是为什么shingling通常用于在集合中找到可以共同用于唯一标识项目的不同迷你区域的原因。
对于图像,您可以使用固定长度的连续RGB值(在这种情况下,从左到右,从上到下,在边缘被击中时缠绕)以生成带状疱疹。在这种情况下,假设一个木瓦长度为3,你的集合看起来像这样(注意我使用方括号来表示属性/向量,因为带状疱疹本身不是集合):
left image = { [r, r, r], [r, r, g], [r, g, g], [g, g, g] }
right image = { [g, g, g], [g, g, r], [g, r, r], [r, r, r] }
并给你一个Jaccard相似度:
intersection(left, right) = 2
union(right, left) = 6
similarity(left, right) = 2 / 6 = 33.33%
这是对这些图像(与之相比)的相似程度的更接近估计。
请注意,带状疱疹可以是您选择的任何长度。你必须决定什么带状疱疹产生适当的Jaccard相似性结果(和阈值)回答“这些有多相似?”的问题。
现在,回答你的第一个问题:
宇宙价值是多少?
在这种特殊情况下,它是Universe中可能存在的项目数。如果您使用单个RGB像素,则Universe将为:
255 * 255 * 255 = 16,581,375
由于你正在处理这些项目的组合,所以价值要高得多。理想情况下,您希望为minhash的哈希函数集生成一组perfect hash functions。但是,由于类型系统的限制(或者,因为您不希望在另一个存储介质中存储非常大的数字),您应该关注最小化冲突的哈希函数。
如果你知道项目世界中可能的项目数量,那么它可以帮助你生成减少碰撞次数的哈希函数。
在implementation that you reference中,此Universe大小用于生成随机数,然后传递这些数字以生成用于minhashing的多个哈希函数,理想情况下,这将产生最小的冲突。
答案 1 :(得分:0)
简而言之,单独使用Minhash是一个很差的解决方案,用于查找类似的图像。与适当的图像特征提取结合使用时,它应该可以正常工作。但这远非直截了当。我会解释一下:
从广义上讲,Minhash根据共享功能的数量计算相似度。选择适当的功能来生成你的minhashes是至关重要的。在您的情况下,您必须选择可能由类似图像共享的功能(但不太可能由不同图像共享)。通过“共享”,我的意思是在两个图像中找到相同的功能相同。
对于文本文档,这很容易:所使用的功能通常是带状疱疹的文本,例如“猫坐着”,“猫坐着”,“坐在垫子上”,“”。这些很容易生成,并且可能在类似文档之间共享。
使用图像会更难。您无法比较字节数,因为同一图像的JPEG和PNG将具有完全不同的字节模式。您也不能比较像素颜色值的运行,因为这些颜色值在JPEG和PNG图像之间会略有不同。然后考虑如果一个图像稍微缩放,模糊或略微旋转,或调整其颜色平衡会发生什么:这些是相似性检测应该强大的所有修改类型,但这些修改都会导致更改对于所有像素,因此如果要素仅基于像素运行,则图像将被视为完全不相似。
图像相似性检测很复杂,并且依赖于使用不随缩放,旋转,裁剪,模糊或实质颜色调整而变化的特征。有许多技术,它们通常检测图像中的宽广形状和颜色关系。这不适合新手,你需要愿意阅读计算机视觉领域的一些相当数学论文。一旦你能够检测到这些功能,就可以将它们有效地输入到minhash算法中并获得良好的结果。
MinHash中的这个宇宙是什么?
该博客的作者显然希望universeSize
成为可能存在的不同功能的数量,但不会对该值产生任何影响。他们只是用它来减少哈希函数的随机性,这总是一个坏主意。出于所有实际目的,宇宙应该被认为是无限的,并且没有理由在minhash实现中使用这样的变量。我在那段代码中看到了很多问题。