我希望创建一个图像基表,然后将任何新图像与之进行比较,以确定新图像是否与基表完全相同(或接近)。
例如:如果你想减少100次相同图像的存储,你可以存储它的一个副本,并提供它的参考链接。当输入一个新图像时,你想要与现有的图像进行比较,以确保它不是重复的…想法吗?
我的一个想法是缩小到一个小缩略图,然后随机选择100个像素位置并进行比较。
我希望创建一个图像基表,然后将任何新图像与之进行比较,以确定新图像是否与基表完全相同(或接近)。
例如:如果你想减少100次相同图像的存储,你可以存储它的一个副本,并提供它的参考链接。当输入一个新图像时,你想要与现有的图像进行比较,以确保它不是重复的…想法吗?
我的一个想法是缩小到一个小缩略图,然后随机选择100个像素位置并进行比较。
当前回答
我认为值得在此基础上添加我构建的phash解决方案,我们已经使用了一段时间:Image:: phash。它是一个Perl模块,但主要部分是用c语言编写的。它比phash.org快几倍,并且为基于dct的phash提供了一些额外的特性。
我们已经在MySQL数据库上建立了数以千万计的图像索引,所以我想要一些快速的东西,也想要一种使用MySQL索引的方法(这与汉明距离不工作),这导致我使用“减少”哈希进行直接匹配,模块文档讨论了这一点。
使用起来很简单:
use Image::PHash;
my $iph1 = Image::PHash->new('file1.jpg');
my $p1 = $iph1->pHash();
my $iph2 = Image::PHash->new('file2.jpg');
my $p2 = $iph2->pHash();
my $diff = Image::PHash::diff($p1, $p2);
其他回答
我所知道的最好的方法是使用感知哈希。似乎有一个很好的开源实现这样的散列可用:
http://phash.org/
其主要思想是,通过识别原始图像文件中的显著特征,并对这些特征进行哈希(而不是直接对图像数据进行哈希),将每张图像简化为一个小的哈希代码或“指纹”。这意味着,相比简单的方法,如将图像缩小到一个小的拇指指纹大小的图像,并比较拇指指纹,假阳性率大大降低。
Phash提供了几种类型的哈希,可用于图像、音频或视频。
几年前,我用PHP编写了一个非常简单的图像比较解决方案。它为每张图像计算一个简单的哈希值,然后找出差值。它的工作非常好裁剪或裁剪与翻译版本的同一图像。
首先,我将图像调整为较小的尺寸,如24x24或36x36。然后我取每一列的像素,并找出这一列的平均R,G,B值。
在每一列都有自己的三个数字之后,我进行两次传递:第一次是奇数列,第二次是偶数列。第一次传递将所有处理过的cols相加,然后除以它们的数([1]+ [2]+ [5]+ [N-1] / (N/2))。第二步以另一种方式进行:([3]-[4]+[6]-[8]…(n /2))。
现在我有两个数。正如我在实验中发现的,第一个是主要的:如果它与另一张图像的值相差甚远,那么从人类的角度来看,它们根本就不相似。
So, the first one represents the average brightness of the image (again, you can pay most attention to green channel, then the red one, etc, but the default R->G->B order works just fine). The second number can be compared if the first two are very close, and it in fact represents the overall contrast of the image: if we have some black/white pattern or any contrast scene (lighted buildings in the city at night, for example) and if we are lucky, we will get huge numbers here if out positive members of sum are mostly bright, and negative ones are mostly dark, or vice versa. As I want my values to be always positive, I divide by 2 and shift by 127 here.
我在2017年用PHP写的代码,似乎我丢失了代码。但我还有截图:
同样的图片:
黑白版:
裁剪版:
另一张图片,翻译版:
和第四色域一样,但另一个场景:
我调整了差异阈值,因此结果非常好。但是正如你所看到的,这个简单的算法对于简单的场景翻译并没有什么好处。
另一方面,我可以注意到,修改可以从两张图像中每一张以75- 80%的比例制作裁剪副本,角落4个,角落和边缘中间8个,然后以同样的方式将裁剪的变体与另一张完整的图像进行比较;如果其中一个相似度得分明显更高,那么就使用它的值而不是默认值)。
I believe that dropping the size of the image down to an almost icon size, say 48x48, then converting to greyscale, then taking the difference between pixels, or Delta, should work well. Because we're comparing the change in pixel color, rather than the actual pixel color, it won't matter if the image is slightly lighter or darker. Large changes will matter since pixels getting too light/dark will be lost. You can apply this across one row, or as many as you like to increase the accuracy. At most you'd have 47x47=2,209 subtractions to make in order to form a comparable Key.
这篇文章是我解决方案的起点,这里有很多好主意,所以我想分享我的结果。主要的见解是,我已经找到了一种方法,通过利用phash的速度来解决基于关键点的图像匹配的缓慢问题。
对于一般的解决方案,最好采用几种策略。每种算法都最适合于某些类型的图像转换,您可以利用这一点。
最上面是最快的算法;底部最慢(虽然更准确)。如果在更快的级别上找到了一个很好的匹配,您可能会跳过慢的级别。
基于文件哈希(md5,sha1等)的精确副本 用于缩放图像的感知哈希(phash) 用于修改图像的基于特征的(SIFT)
我的phash治疗效果很好。该方法对缩放后的图像具有较好的精度。它不适用于(感知上)修改过的图像(裁剪、旋转、镜像等)。为了处理散列速度,我们必须使用磁盘缓存/数据库来维护干草堆的散列。
phash真正的好处是,一旦你建立了哈希数据库(对我来说大约是1000张图片/秒),搜索可以非常非常快,特别是当你可以把整个哈希数据库保存在内存中时。这是相当实用的,因为哈希只有8个字节。
例如,如果您有100万张图像,则需要100万64位哈希值(8 MB)的数组。在某些cpu上,这适用于L2/L3缓存!在实际使用中,我看到corei7的速度超过1千兆哈姆/秒,这只是CPU内存带宽的问题。一个10亿张图片的数据库在64位CPU(需要8GB内存)上是可行的,搜索不会超过1秒!
For modified/cropped images it would seem a transform-invariant feature/keypoint detector like SIFT is the way to go. SIFT will produce good keypoints that will detect crop/rotate/mirror etc. However the descriptor compare is very slow compared to hamming distance used by phash. This is a major limitation. There are a lot of compares to do, since there are maximum IxJxK descriptor compares to lookup one image (I=num haystack images, J=target keypoints per haystack image, K=target keypoints per needle image).
为了解决速度问题,我尝试在每个找到的关键点周围使用phash,使用特征大小/半径来确定子矩形。使此工作良好的技巧是增加/缩小半径以生成不同的子矩形水平(在针图像上)。通常情况下,第一个级别(未缩放)将匹配,但通常需要更多。我不是100%确定为什么这是有效的,但我可以想象它可以实现对phash来说太小的功能(phash将图像缩小到32x32)。
另一个问题是SIFT不能最优地分配关键点。如果图像中有一个区域有很多边缘,那么关键点就会聚集在那里,而在其他区域则不会出现任何边缘。我在OpenCV中使用GridAdaptedFeatureDetector来改进分发。不知道什么网格大小是最好的,我使用一个小网格(1x3或3x1取决于图像方向)。
你可能想要在特征检测之前将所有的草堆图像(和针)缩放到更小的尺寸(我在最大尺寸上使用210px)。这将减少图像中的噪声(一直是计算机视觉算法的一个问题),也将探测器聚焦在更突出的特征上。
对于人物图像,您可以尝试面部检测并使用它来确定要缩放的图像大小和网格大小(例如最大的人脸缩放为100px)。特征检测器考虑多个等级(使用金字塔),但它将使用多少等级是有限制的(当然这是可调的)。
关键点检测器可能在返回的特性数量少于您想要的特性数量时工作得最好。例如,如果你要求400,得到300,那很好。如果你每次都能拿回400块,那么一些好的功能就会被忽略掉。
针状图像可以比干草堆图像拥有更少的关键点,但仍然可以获得良好的结果。增加更多并不一定能让你获得巨大的收益,例如当J=400和K=40时,我的命中率约为92%。当J=400和K=400时,命中率只能上升到96%。
我们可以利用汉明函数的极快速度来解决缩放、旋转、镜像等问题。可以使用多通道技术。在每次迭代中,转换子矩形,重新散列,并再次运行搜索函数。
I have an idea, which can work and it most likely to be very fast. You can sub-sample an image to say 80x60 resolution or comparable, and convert it to grey scale (after subsampling it will be faster). Process both images you want to compare. Then run normalised sum of squared differences between two images (the query image and each from the db), or even better Normalised Cross Correlation, which gives response closer to 1, if both images are similar. Then if images are similar you can proceed to more sophisticated techniques to verify that it is the same images. Obviously this algorithm is linear in terms of number of images in your database so even though it is going to be very fast up to 10000 images per second on the modern hardware. If you need invariance to rotation, then a dominant gradient can be computed for this small image, and then the whole coordinate system can be rotated to canonical orientation, this though, will be slower. And no, there is no invariance to scale here.
如果你想要更一般的东西或使用大数据库(百万张图片),那么 你需要研究图像检索理论(在过去5年里出现了大量的论文)。 在其他答案中有一些提示。但这可能有点过头了,建议直方图方法就可以了。尽管我认为是多种不同的组合 快速的方法会更好。