Часто в задачах Computer Vision у нас есть модель интересной формы, и мы хотим знать, совпадает ли эта модель с целевой формой, найденной путем анализа краев изображения. Форма цели никогда не идентична имеющейся у нас модели, потому что она может быть представлением модели в другой позе или может лишь частично соответствовать нашей модели, поэтому мы должны найти правильное преобразование модели, чтобы соответствовать цель. В этом посте мы увидим, как найти модель, ближайшую к целевой фигуре, используя функцию fmin, предоставляемую Scipy.
Мы можем представить форму с помощью матрицы, как показано ниже:
где каждая пара (x i , y i ) является «ориентиром» точки фигуры, и мы можем преобразовать каждую общую точку (x, y), используя эту функцию:
В этом преобразовании мы имеем, что θ — угол поворота, t x и t y — сдвиг по оси x и y соответственно, а s — коэффициент масштабирования. Применяя это преобразование к каждой точке формы, описанной X, мы получаем новую форму, которая является преобразованием исходной формы в соответствии с параметрами, используемыми в T. Учитывая матрицу, как определено выше, следующая функция Python способна применить преобразование к каждой точке формы, представленной матрицей:
import numpy as np import pylab as pl from scipy.optimize import fmin def transform(X,theta,tx=0,ty=0,s=1):""" Performs scaling, rotation and translation on the set of points in the matrix X Input: X, points (each row have to be a point [x, y]) theta, rotation angle (in radiants) tx, translation along x ty, translation along y s, scaling coefficient Return: Y, transformed set of points """ a = math.cos(theta) b = math.sin(theta) R = np.mat([[a*s,-b*s],[b*s, a*s]]) Y = R*X # rotation and scaling Y[0,:]= Y[0,:]+tx # translation Y[1,:]= Y[1,:]+ty return Y
Теперь мы хотим найти лучшую позу (перемещение, масштаб и вращение), чтобы сопоставить форму модели X с целевой формой Y. Мы можем решить эту проблему, сводя к минимуму сумму квадратных расстояний между точками X и Y, а это значит, что мы хотим найти
где T ‘- это функция, которая применяет T ко всем точкам входной фигуры. Эта задача оказывается довольно простой, используя функцию fmin, предоставляемую Scipy:
def error_fun(p,X,Y):""" cost function to minimize """return np.linalg.norm(transform(X,p[0],p[1],p[2],p[3])-Y)def match(X,Y,p0):""" Match the model X with the shape Y returns the set of parameters to transform X into Y and a set of partial solutions. """ p_opt = fmin(error_fun, p0, args=(X,Y),retall=True)return p_opt[0],p_opt[1]# optimal solutions, other solutions
В приведенном выше коде мы определили функцию стоимости, которая измеряет, насколько близки две фигуры, и другую функцию, которая минимизирует разницу между двумя фигурами и возвращает параметры преобразования. Теперь мы можем попытаться сопоставить форму трилистника, начиная с одного из ее преобразований, используя функции, определенные выше:
# generating a shape to match t = np.linspace(0,2*np.pi,50) x =2*np.cos(t)-.5*np.cos(4*t ) y =2*np.sin(t)-.5*np.sin(4*t ) A = np.array([x,y])# model shape# transformation parameters p =[-np.pi/2,.5,.8,1.5]# theta,tx,ty,sAr= transform(A,p[0],p[1],p[2],p[3])# target shape p0 = np.random.rand(4)# random starting parameters p_opt, allsol = match(A,Ar,p0)# matching
Интересно визуализировать ошибку на каждой итерации:
pl.plot([error_fun(s,A,Ar)for s in allsol]) pl.show()
и значение параметров преобразования на каждой итерации:
pl.plot(allsol) pl.show()
Из приведенных выше графиков видно, что процесс минимизации нашел свое решение после 150 итераций. Действительно, после 150 итераций ошибка становится очень близкой к нулю, и параметры практически не изменяются. Теперь мы можем визуализировать процесс минимизации, отображая некоторые решения, чтобы сравнить их с целевой формой:
def plot_transform(A,p):Afound= transform(A,p[0],p[1],p[2],p[3]) pl.plot(Afound[0,:].T,Afound[1,:].T,'-')for k,i in enumerate(range(0,len(allsol),len(allsol)/15)): pl.subplot(4,4,k+1) pl.plot(Ar[0,:].T,Ar[1,:].T,'--',linewidth=2)# target shape plot_transform(A,allsol[i]) pl.axis('equal') pl.show()
На графике выше мы видим, что исходные решения (зеленые) очень отличаются от формы, которую мы пытаемся сопоставить (пунктирные синие), и что в процессе минимизации они приближаются к целевой фигуре, пока не подойдут это полностью. В приведенном выше примере мы использовали две фигуры одинаковой формы. Давайте посмотрим, что произойдет, когда у нас будет начальная форма, которая отличается от целевой модели:
t = np.linspace(0,2*np.pi,50) x = np.cos(t) y = np.sin(t)Ac= np.array([x,y])# the circle (model shape) p0 = np.random.rand(4)# random starting parameters# the target shape is the trifoil again p_opt, allsol = match(Ac,Ar,p0)# matching
В приведенном выше примере мы использовали круг в качестве модельной фигуры и трилистник в качестве целевой фигуры. Давайте посмотрим, что произошло в процессе минимизации:
for k,i in enumerate(range(0,len(allsol),len(allsol)/15)): pl.subplot(4,4,k+1) pl.plot(Ar[0,:].T,Ar[1,:].T,'--',linewidth=2)# target shape plot_transform(Ac,allsol[i]) pl.axis('equal') pl.show()
В этом случае, когда форма модели не может полностью соответствовать целевой форме, мы видим, что процесс минимизации может найти круг, который находится ближе к трилистнику.