我想使用“地球移动距离”来比较多个图像。
我将scipy.stats.wasserstein_distance()
与pyemd.emd_samples()
进行了比较。
据我了解,wasserstein_distance()
采用两种分布,即直方图,而emd_samples()
采用一维值数组并为您计算直方图。
鉴于两种方法都使用相同的直方图,它们应提供相同或至少相似的结果。
问题在于,两种方法都提供了截然不同的结果。但是,如果我通过这两种方法传递图像的展平版本,结果将非常相似。
我这方面有错误还是这些实现之一有问题?
cat1 = skimage.io.imread("./cat1.jpg", as_grey=True).flatten().astype('float64')
cat2 = skimage.io.imread("./cat2.jpg", as_grey=True).flatten().astype('float64')
shuttle = skimage.io.imread("./shuttle.jpg", as_grey=True).flatten().astype('float64')
emd_s = np.array([[emd_samples(cat1, cat1, bins="fd"), emd_samples(cat1, cat2, bins="fd"), emd_samples(cat1, shuttle, bins="fd")],
[emd_samples(cat2, cat1, bins="fd"), emd_samples(cat2, cat2, bins="fd"), emd_samples(cat2, shuttle, bins="fd")],
[emd_samples(shuttle, cat1, bins="fd"), emd_samples(shuttle, cat2, bins="fd"), emd_samples(shuttle, shuttle, bins="fd")]])
pmf_cat1, bins_cat1 = np.histogram(cat1 , bins="fd")
pmf_cat2, bins_cat2 = np.histogram(cat2 , bins="fd")
pmf_shuttle, bins_shuttle = np.histogram(shuttle , bins="fd")
emd_s2 = np.array([[emd_samples(pmf_cat1, pmf_cat1, bins="fd"), emd_samples(pmf_cat1, pmf_cat2, bins="fd"), emd_samples(pmf_cat1, pmf_shuttle, bins="fd")],
[emd_samples(pmf_cat2, pmf_cat1, bins="fd"), emd_samples(pmf_cat2, pmf_cat2, bins="fd"), emd_samples(pmf_cat2, pmf_shuttle, bins="fd")],
[emd_samples(pmf_shuttle, pmf_cat1, bins="fd"), emd_samples(pmf_shuttle, pmf_cat2, bins="fd"), emd_samples(pmf_shuttle, pmf_shuttle, bins="fd")]])
swd = np.array([[wasserstein_distance(pmf_cat1, pmf_cat1), wasserstein_distance(pmf_cat1, pmf_cat2), wasserstein_distance(pmf_cat1, pmf_shuttle)],
[wasserstein_distance(pmf_cat2, pmf_cat1), wasserstein_distance(pmf_cat2, pmf_cat2), wasserstein_distance(pmf_cat2, pmf_shuttle)],
[wasserstein_distance(pmf_shuttle, pmf_cat1), wasserstein_distance(pmf_shuttle, pmf_cat2), wasserstein_distance(pmf_shuttle, pmf_shuttle)]])
swd2 = np.array([[wasserstein_distance(cat1, cat1), wasserstein_distance(cat1, cat2), wasserstein_distance(cat1, shuttle)],
[wasserstein_distance(cat2, cat1), wasserstein_distance(cat2, cat2), wasserstein_distance(cat2, shuttle)],
[wasserstein_distance(shuttle, cat1), wasserstein_distance(shuttle, cat2), wasserstein_distance(shuttle, shuttle)]])
上面的示例对
emd_s
和swd2
产生了相似的结果,并且对emd_s2
和swd
产生了相似的结果,尽管最后一对仍然有很大的不同,因为技术上emd_samples
应该在此基于直方图绘制直方图案件。 最佳答案
我遇到了一个类似的问题,在这里要注意几件事。
函数emd_samples
和wasserstein_distance
都将(经验)分布中观察到的值作为输入,而不是分布本身。
函数emd
允许您传递分布,但是,您需要提供度量作为附加参数。同样,在使用直方图作为(密度)分布时,您需要对其进行归一化。
不展平灰度图像意味着您比较仅适用于pyemd
的2D直方图。
用法示例:
import numpy as np
import skimage
import os
from pyemd import emd, emd_samples
from scipy.stats import wasserstein_distance
# get some test images
img1 = skimage.io.imread(os.path.join(skimage.data_dir, 'astronaut.png'))
img2 = skimage.io.imread(os.path.join(skimage.data_dir, 'camera.png'))
img3 = skimage.io.imread(os.path.join(skimage.data_dir, 'horse.png'))
# flatten them
images = [img.ravel() for img in [img1, img2, img3]]
# compute EMD using values
emd_samples(images[0], images[1]) # 25.57794401220945
wasserstein_distance(images[0], images[1]) # 25.76187896728515
# compute EMD using distributions
N_BINS = 256
hists = [np.histogram(img, N_BINS, density=True)[0].astype(np.float64) for img in images]
mgrid = np.meshgrid(np.arange(N_BINS), np.arange(N_BINS))
metric = np.abs(mgrid[0] - mgrid[1]).astype(np.float64)
emd(hists[0], hists[1], metric) # 25.862491463680065