Python - 地球移动距离

3
我想使用地球移动距离(Earth Movers Distance)来比较多张图片。
我比较了 scipy.stats.wasserstein_distance()pyemd.emd_samples() 两种方法。据我所知,wasserstein_distance() 接受两个分布(即直方图),而 emd_samples() 接受一个1D值数组并为您计算直方图。
鉴于这两种方法使用相同的直方图,它们应该提供相同或至少类似的结果。
问题在于,这两种方法提供的结果非常不同。但是,如果我在这两种方法中都传递我的图像的扁平版本,则结果非常相似。

是我的问题还是其中一种实现存在问题?

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 应该基于直方图制作直方图。请保留 HTML 标记。

1
请展示如何调用这两个函数(注意:最小、完整和可验证的示例)。 - MB-F
@Xenthor,emd_samples() 函数来自哪里? - duhaime
这个项目 https://github.com/wmayner/pyemd - Xenthor
1个回答

2

我遇到了类似的问题,想在这里注明几点事项:

  1. emd_samples函数和wasserstein_distance函数都需要输入(经验)分布中观察到的值,而不是分布本身。

  2. emd函数允许你传递分布,但你需要提供度量作为额外的参数。另外,当使用直方图作为(密度)分布时,你需要对它们进行归一化。

  3. 不将灰度图像压平意味着你比较的是二维直方图,这只能使用pyemd来实现。

示例用法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接