地球搬运工距离的Python代码

18 投票
3 回答
22468 浏览
提问于 2025-04-16 12:26

我在找一个用Python实现的地球移动者距离(或者叫快速EMD)的代码。有没有人知道在哪里可以找到?我在网上找了很多地方。

我想在我正在做的图像检索项目中使用它。谢谢。

补充说明:
我找到了一种很不错的解决方案,使用了pulp库。这个页面上还有设置的说明。

3 个回答

0

Python Optimal Transport库是一个工具,它提供了几种方法来解决与最优运输相关的优化问题,这些问题通常出现在信号处理、图像处理和机器学习中。

2

这里是用Python计算两个相同长度的一维分布之间的地球搬运工距离的代码。

def emd (a,b):
earth = 0
earth1 = 0
diff = 0
s= len(a)
su = []
diff_array = []
for i in range (0,s):
    diff = a[i]-b[i]
    diff_array.append(diff)
    diff = 0
for j in range (0,s):
    earth = (earth + diff_array[j])
    earth1= abs(earth)
    su.append(earth1)
emd_output = sum(su)/(s-1)
print(emd_output)
28

在Python中,有一个很棒的实现来自OpenCv。这个函数叫做CalcEMD2,用来比较两张图片的直方图,简单的代码大概是这样的:

#Import OpenCv library
from cv2 import *

### HISTOGRAM FUNCTION #########################################################
def calcHistogram(src):
    # Convert to HSV
    hsv = cv.CreateImage(cv.GetSize(src), 8, 3)
    cv.CvtColor(src, hsv, cv.CV_BGR2HSV)

    # Extract the H and S planes
    size = cv.GetSize(src)
    h_plane = cv.CreateMat(size[1], size[0], cv.CV_8UC1)
    s_plane = cv.CreateMat(size[1], size[0], cv.CV_8UC1)
    cv.Split(hsv, h_plane, s_plane, None, None)
    planes = [h_plane, s_plane]

    #Define numer of bins
    h_bins = 30
    s_bins = 32

    #Define histogram size
    hist_size = [h_bins, s_bins]

    # hue varies from 0 (~0 deg red) to 180 (~360 deg red again */
    h_ranges = [0, 180]

    # saturation varies from 0 (black-gray-white) to 255 (pure spectrum color)
    s_ranges = [0, 255]

    ranges = [h_ranges, s_ranges]

    #Create histogram
    hist = cv.CreateHist([h_bins, s_bins], cv.CV_HIST_ARRAY, ranges, 1)

    #Calc histogram
    cv.CalcHist([cv.GetImage(i) for i in planes], hist)

    cv.NormalizeHist(hist, 1.0)

    #Return histogram
    return hist

### EARTH MOVERS ############################################################
def calcEM(hist1,hist2,h_bins,s_bins):

    #Define number of rows
    numRows = h_bins*s_bins

    sig1 = cv.CreateMat(numRows, 3, cv.CV_32FC1)
    sig2 = cv.CreateMat(numRows, 3, cv.CV_32FC1)    

    for h in range(h_bins):
        for s in range(s_bins): 
            bin_val = cv.QueryHistValue_2D(hist1, h, s)
            cv.Set2D(sig1, h*s_bins+s, 0, cv.Scalar(bin_val))
            cv.Set2D(sig1, h*s_bins+s, 1, cv.Scalar(h))
            cv.Set2D(sig1, h*s_bins+s, 2, cv.Scalar(s))

            bin_val = cv.QueryHistValue_2D(hist2, h, s)
            cv.Set2D(sig2, h*s_bins+s, 0, cv.Scalar(bin_val))
            cv.Set2D(sig2, h*s_bins+s, 1, cv.Scalar(h))
            cv.Set2D(sig2, h*s_bins+s, 2, cv.Scalar(s))

    #This is the important line were the OpenCV EM algorithm is called
    return cv.CalcEMD2(sig1,sig2,cv.CV_DIST_L2)

### MAIN ########################################################################
if __name__=="__main__":
    #Load image 1
    src1 = cv.LoadImage("image1.jpg")

    #Load image 1
    src2 = cv.LoadImage("image2.jpg")

    # Get histograms
    histSrc1= calcHistogram(src1)
    histSrc2= calcHistogram(src2)

    # Compare histograms using earth mover's
    histComp = calcEM(histSrc1,histSrc2,30,32)

    #Print solution
    print(histComp)

我用Python 2.7和Python(x,y)测试过一段和上面代码很相似的代码。如果你想了解更多关于地球搬运工算法的内容,并且想看看用OpenCV和C++实现的例子,可以阅读Gary Bradski和Adrain Kaebler的书《Learning OpenCV》第七章:“直方图与匹配”。

撰写回答