Код Python для расстояния движителя Земли
Я ищу реализацию расстояния (или быстрого EMD) Earth Mover в Python. Любые подсказки о том, где его найти, я достаточно посмотрел в Интернете. Я хочу использовать его в проекте поиска изображений, который я делаю. Благодарю.
РЕДАКТИРОВАТЬ: Я нашел очень хорошее решение, используя библиотеки целлюлозы. Эта страница также содержит инструкции, необходимые для ее настройки.
4 ответа
В OpenCv есть отличная реализация для Python. Название функции - 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). Если вы хотите узнать больше о Earth Mover и увидеть реализацию, использующую OpenCV и C++, вы можете прочитать "Глава 7: Соответствие гистограмм" книги "Изучение OpenCV" Гари Брадски и Адрейна Кеблера.
Поиск в Google показал мне эту ссылку - http://www.cs.huji.ac.il/~ofirpele/FastEMD/code/. Может быть, вы можете сделать больше исследований здесь и перенести код C/Matlab в Python
вот код 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)
Расстояние от землеройной машины (EMD) также называется метрикой Вассерштейна. Для этого вы можете получить реализацию Python от scipy.stats
:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.wasserstein_distance.html