比较两个直方图
image-processing
9
0

对于一个小型项目,我需要将一个图像与另一个图像进行比较-确定图像是否大致相同。图像很小,从25像素到100像素不等。这些图像本应具有相同的图片数据,但存在细微差别,因此简单的像素相等性检查将无法进行。请考虑以下两种可能的情况:

  1. 博物馆中的一个监视摄像机的安全(CCTV)摄像机:我们想快速查看两个不同的视频帧是否显示相同的场景,但是照明和摄像机焦点的细微差异意味着它们将是不同的。
  2. 与以48x48呈现的相同图标相比,矢量计算机GUI图标的图片(以48x48呈现的同一图标)(但两个图像都将缩小为32x32,因此直方图具有相同的总像素数)。

我已决定使用直方图来表示每个图像,并使用三个1D直方图:每个RGB通道一个-可以安全地使用颜色,而忽略纹理和边缘直方图(另一种方法是对每个图像使用一个3D直方图,但我避免这样做,因为这会增加额外的复杂性。因此,我将需要比较直方图以了解它们的相似度,如果相似性度量值超过某个阈值,那么我可以放心地说各个图像在视觉上是相同的-我将比较每个图像的相应通道直方图(例如图像1的红色直方图与图像2的红色直方图,然后图像1的蓝色直方图与图像2的蓝色直方图,然后是绿色直方图-因此,我没有将图像1的红色直方图与图像2的蓝色直方图进行比较,这太愚蠢了。

假设我有这三个直方图,它们代表三个图像的红色RGB通道的摘要(为简单起见,对7个像素的图像使用5个bin):

H1            H2            H3 

  X           X                     X
  X   X       X       X             X
X X   X X     X X   X X     X X X X X
0 1 2 3 4     0 1 2 3 4     0 1 2 3 4

H1 = [ 1, 3, 0, 2, 1 ]
H2 = [ 3, 1, 0, 1, 2 ]
H3 = [ 1, 1, 1, 1, 3 ] 

图像1( H1 )是我的参考图像,我想查看图像2( H2 )和/或图像3( H3 )是否与图像1类似。请注意,在此示例中,图像2与图像1相似,但是图片3不是。

当我粗略搜索“直方图差异”算法(至少我能理解的算法)时,我发现一种流行的方法是仅求和每个仓之间的差,但是这种方法通常会失败,因为它会加权所有仓差异。

为了演示这种方法的问题,请使用C#代码,如下所示:

Int32[] image1RedHistogram = new Int32[] { 1, 3, 0, 2, 1 };
Int32[] image2RedHistogram = new Int32[] { 3, 2, 0, 1, 2 };
Int32[] image3RedHistogram = new Int32[] { 1, 1, 1, 1, 3 };

Int32 GetDifference(Int32[] x, Int32[] y) {
    Int32 sumOfDifference = 0;
    for( int i = 0; i < x.Length; i++ ) {
        sumOfDifference += Math.Abs( x[i] - y[i] );
    }
    return sumOfDifferences;
}

输出为:

GetDifference( image1RedHistogram, image2RedHistogram ) == 6
GetDifference( image1RedHistogram, image3RedHistogram ) == 6

这是不正确的。

有没有一种方法可以在考虑分布形状的情况下确定两个直方图之间的差异?

参考资料:
Stack Overflow
收藏
评论
共 6 个回答
高赞 时间 活跃

通过将输入直方图中每个bin中的值除以直方图所基于的像素总数,可以对直方图进行归一化。然后使用@tkerwin的EMD

收藏
评论

您基本上想看一个概率距离 。有很多,您必须决定哪个适合您的应用程序。最近,我对卡方和Kullback-Leibler感到很幸运。

收藏
评论

推土机距离(EMD)通常用于这种直方图比较。 EMD使用一个值来定义将像素从直方图的一个箱“移动”到另一箱的成本,并提供将特定直方图转换为目标直方图的总成本。垃圾桶越远,成本越高。

在您的示例中,将5个单位从red [0]移至红色1将花费(c*1*5)而将5个单位从red [0]移至红色[10]将花费(c*10*5)

有几种实现方式。 FastEMD具有C ++,Java和Matlab的代码。我相信OpenCV也有一些支持。

使用这种技术发表了许多关于大型图像数据库相似性搜索的论文。

收藏
评论

直方图的比较本身就是一个主题。

您有两大类比较功能:箱到箱比较和跨箱比较。

  • 仓对仓比较:如您所述,标准差之和非常差。 卡方距离有一个改进,即如果H1.red[0] = 0.001 and H2.red[0] = 0.011则比H1.red[0] = 0.1 and H2.red[0] = 0.11 ,即使在两种情况下|H1.red[0] - H2.red[0]| = 0.01
  • 跨箱比较:称为箱相似度矩阵的标准示例需要一些相似度矩阵M,其中M(i,j)是箱i与箱j之间的相似度。假设bin[i]是红色的。如果bin[j]为深红色,则M(i,j)大。如果bin[j]为绿色,则M(i,j)小。然后,直方图H1和H2之间的距离将为sqrt((H1-H2)*M*(H1-H2)) 。此方法考虑了您所说的“关闭”垃圾箱! 地面移动距离 (EMD)是另一种交叉箱距离。

最后,我要指出三点:

  • 您应该阅读有关直方图距离的本文 。这很容易,并向您介绍了直方图的距离。第1章很好地总结了我所讨论的所有距离。老实说,文章中描述的最后一件事并不是那么复杂,但是对于您的情况来说可能太过分了。
  • 跨仓距离非常好,但是可能会很昂贵(即:计算时间长,因为它涉及矩阵,因此为O(n ^ 2))。规避昂贵的交叉仓计算(并且已广泛完成)的最简单方法是进行一些软分配:如果像素为红色,则应填充所有看起来像红色的仓(当然,要提供更多权重到最接近的颜色)。然后,您可以使用bin-to-bin算法。
  • 多以数学为中心:上一点是关于将跨箱比较简化为箱对箱比较。事实上,它是由隐式角化相似度矩阵M.如果可以对角化M = P'*D*P ,其中P'是转置P ,然后sqrt((H1-H2)'*M*(H1-H2)) = sqrt((H1-H2)'*P'*D*P*(H1-H2)) = sqrt((P(H1-H2))'*D*(P(H1-H2))) 。根据您计算P(H1-H2) ,这可以节省您的计算时间。直观地,如果H1是您的原始直方图,则P*H1是一个软分配,并且您使用的是隐式相似性矩阵M = P'*Id*P
收藏
评论

在比较直方图时,我发现卡方检验是一个不错的起点。如果每个直方图中的条目数都不相同,则必须更加小心,因为您无法使用“正常”表达式。从内存中,如果您假设直方图的条目数不相等,则卡方检验可概括为

1 /(MN)SUM_i [(((Mni-Nmi)^ 2)/(mi + ni)]。

M和N是每个直方图中的条目总数,mi是直方图M的bin i中的条目数,ni是直方图N的bin i中的条目数。

另一个测试是Kolmogorov-Smirnov测试。该测试着眼于两个直方图的累积概率分布之间的最大差异。这很难实现,我认为C语言中的数字配方在C语言中有一个代码段,并且我肯定在Matlab中可以做到这一点。如果您对直方图形状的差异更感兴趣,而不是确切的值,那么对它的非参数而言可能是更好的测试。

收藏
评论

我很惊讶没有人提到直方图比较的opencv实现,并且可以轻松处理不同格式(uchar,float,double等)的多通道图像(灰度,rgb,rgba等)

包括Bhattacharyya距离,卡方,相关和相交方法。你可以找到

compareHist(InputArray H1, InputArray H2, int method)

功能在这里的手册中。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题