python + opencv-如何正确比较图像(通过直方图)?

时间:2019-04-06 16:59:57

标签: python image opencv comparison histogram

我想整理一堆图像(来自MC Escher系列),所以我想到的第一步是通过比较它们将它们归类(您知道,有些具有不同的分辨率/形状等)。

我写了一个非常残酷的脚本来: *阅读文件 *计算他们的直方图 *比较它们

但是比较的质量确实很低,例如匹配的文件完全不同

看看我到目前为止写的东西:

准备直方图

files_hist = {}

for i, f in enumerate(files):
    try:
        frame = cv2.imread(f)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        hist = cv2.calcHist([frame],[0],None,[4096],[0,4096])
        cv2.normalize(hist, hist, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)

        files_hist[f] = hist
    except Exception as e:
        print('ERROR:', f, e)

比较直方图

pairs = list(itertools.combinations(files_hist.keys(), 2))

for i, (f1, f2) in enumerate(pairs):
    correl = cv2.compareHist(files_hist[f1], files_hist[f2], cv2.HISTCMP_CORREL)

    if correl >= 0.999:
        print('MATCH:', correl, f1, f2)

现在,例如,我得到了这两个文件的匹配项:

m._c._escher_244_(1933).jpg m._c._escher_244_(1933).jpg

m._c._escher_208_(1931).jpg m._c._escher_208_(1931).jpg

及其相关性(使用上面的代码)为0.9996699595530539(因此它们实际上是相同的:()

我在做什么错?我如何改进该代码以避免这种错误匹配?

谢谢!

1 个答案:

答案 0 :(得分:2)

直方图不是比较图像的好方法,例如,在黑白图像中,如果它们具有相同数量的黑色像素,则无论图像中的像素分布如何,直方图都将相同(这就是为什么您提到的图像被归类为几乎相等。

有更好的方法来量化图像之间的差异,this post提到了一个不错的选择:

  • 将两个图像都加载为数组(scipy.misc.imread),然后计算逐个元素(逐像素)差异。计算差异的范数。

编辑:

回答一些问题:

  

我认为每个像素的零范数将是0.0-1.0值,值接近0.0意味着“图像相同”,对吗?

接近0.0的值表示像素相同。要比较整个图像,您需要对所有像素求和。如果总和值接近0.0,则表示图像几乎相同。

  

两个图像大小不同怎么办?

那是一个很好的选择。要计算标准差,图像必须具有相同的大小。我看到两种方法可以实现这一目标:

  • 第一个方法是将一个图像调整为另一个图像的形状,问题是这会导致图像失真。

  • 第二个是将较小的图像填充为零,直到大小匹配为止。

obs:如果对像素范数进行求和,则将得到一个介于零和图像像素数之间的值。如果要比较多个图像,这可能会造成混淆。例如,假设您正在比较图像A和B,并且两者的形状均为50x50(因此,图像的像素为2500);值接近2500表示图像完全不同。现在假设您正在比较图像C和D,它们的形状均为1000x1000,在这种情况下,值2500表示图像相似。要解决此问题,您可以将按像素计算的总和除以图像中的像素数,这将得出0.0到1.0之间的值,0.0表示图像相同,而1.0表示它们完全不同。

  

是的,这是我在比较2张具有不同尺寸diff = image1 - image2 ValueError: operands could not be broadcast together with shapes (850,534) (663,650)的图像时收到的错误

这是因为图像具有不同的形状。调整大小或填充可以避免此错误(如上所述)。