I am trying to implement a gradient descent algorithm for simple linear regression. For some reason it doesn't seem to be working.
from __future__ import division
import random
def error(x_i,z_i, theta0,theta1):
return z_i - theta0 - theta1 * x_i
def squared_error(x_i,z_i,theta0,theta1):
return error(x_i,z_i,theta0,theta1)**2
def mse_fn(x, z, theta0,theta1):
m = 2 * len(x)
return sum(squared_error(x_i,z_i,theta0,theta1) for x_i,z_i in zip(x,z)) / m
def mse_gradient(x, z, theta0,theta1):
m = 2 * len(x)
grad_0 = sum(error(x_i,z_i,theta0,theta1) for x_i,z_i in zip(x,z)) / m
grad_1 = sum(error(x_i,z_i,theta0,theta1) * x_i for x_i,z_i in zip(x,z)) / m
return grad_0, grad_1
def minimize_batch(x, z, mse_fn, mse_gradient_fn, theta0,theta1,tolerance=0.000001):
step_sizes = 0.01
theta0 = theta0
theta1 = theta1
value = mse_fn(x,z,theta0,theta1)
while True:
grad_0, grad_1 = mse_gradient(x,z,theta0,theta1)
next_theta0 = theta0 - step_sizes * grad_0
next_theta1 = theta1 - step_sizes * grad_1
next_value = mse_fn(x,z,next_theta0,theta1)
if abs(value - next_value) < tolerance:
return theta0, theta1
else:
theta0, theta1, value = next_theta0, next_theta1, next_value
#The data
x = [i + 1 for i in range(40)]
y = [random.randrange(1,30) for i in range(40)]
z = [2*x_i + y_i + (y_i/7) for x_i,y_i in zip(x,y)]
theta0, theta1 = [random.randint(-10,10) for i in range(2)]
q = minimize_batch(x,z,mse_fn, mse_gradient, theta0,theta1,tolerance=0.000001)
When I run I get the following error:
return error(x_i,z_i,theta0,theta1)**2 OverflowError: (34, 'Result too large')
Related
I am using IPOPT via Pyomo (the AMPL interface) to solve a simple problem and am trying to validate that the primal Lagrangian gradient is zero at the solution. I'm running the following script, in which I construct what I would expect to be the gradient of the Lagrangian with respect to primal variables.
import pyomo.environ as pyo
from pyomo.common.collections import ComponentMap
m = pyo.ConcreteModel()
m.ipopt_zL_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
m.ipopt_zU_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
m.ipopt_zL_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
m.ipopt_zU_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)
m.v1 = pyo.Var(initialize=-2.0)
m.v2 = pyo.Var(initialize=2.0)
m.v3 = pyo.Var(initialize=2.0)
m.v1.setlb(-10.0)
m.v2.setlb(1.5)
m.v1.setub(-1.0)
m.v2.setub(10.0)
m.eq_con = pyo.Constraint(expr=m.v1*m.v2*m.v3 - 2.0 == 0)
obj_factor = 1
m.obj = pyo.Objective(
expr=obj_factor*(m.v1**2 + m.v2**2 + m.v3**2),
sense=pyo.minimize,
)
solver = pyo.SolverFactory("ipopt")
solver.solve(m, tee=True)
grad_lag_map = ComponentMap()
grad_lag_map[m.v1] = (
(obj_factor*2*m.v1) + m.dual[m.eq_con]*m.v2*m.v3 +
m.ipopt_zL_out[m.v1] + m.ipopt_zU_out[m.v1]
)
grad_lag_map[m.v2] = (
(obj_factor*2*m.v2) + m.dual[m.eq_con]*m.v1*m.v3 +
m.ipopt_zL_out[m.v2] + m.ipopt_zU_out[m.v2]
)
grad_lag_map[m.v3] = (
(obj_factor*2*m.v3) + m.dual[m.eq_con]*m.v1*m.v2
)
for var, expr in grad_lag_map.items():
print(var.name, pyo.value(expr))
According to this, however, the gradient of the Lagrangian is not zero when constructed in this way. I can get the gradient of the Lagrangian to be zero by using the following lines to construct grad_lag_map
grad_lag_map[m.v1] = (
-(obj_factor*2*m.v1) + m.dual[m.eq_con]*m.v2*m.v3 +
m.ipopt_zL_out[m.v1] + m.ipopt_zU_out[m.v1]
)
grad_lag_map[m.v2] = (
-(obj_factor*2*m.v2) + m.dual[m.eq_con]*m.v1*m.v3 +
m.ipopt_zL_out[m.v2] + m.ipopt_zU_out[m.v2]
)
grad_lag_map[m.v3] = (
-(obj_factor*2*m.v3) + m.dual[m.eq_con]*m.v1*m.v2
)
With a minus sign in front of the objective gradient, the gradient of the Lagrangian is zero. This is surprising to me. I would not expect to see this factor of -1 for minimization problems. Can anybody confirm whether IPOPT constructs its Lagrangian with this -1 factor for minimization problems, or whether this is the artifact of some other convention I am unaware of?
This is the Gradient of the Lagrangian w.r.t. x computed in Ipopt (https://github.com/coin-or/Ipopt/blob/2b1a2f9a60fb3f8426b47edbe3b3520c7335d201/src/Algorithm/IpIpoptCalculatedQuantities.cpp#L2018-L2023):
tmp->Copy(*curr_grad_f());
tmp->AddTwoVectors(1., *curr_jac_cT_times_curr_y_c(), 1., *curr_jac_dT_times_curr_y_d(), 1.);
ip_nlp_->Px_L()->MultVector(-1., *z_L, 1., *tmp);
ip_nlp_->Px_U()->MultVector(1., *z_U, 1., *tmp);
This corresponds to an Ipopt-internal representation of a NLP, which has the form
min f(x) dual vars:
s.t. c(x) = 0, y_c
d(x) - s = 0, y_d
d_L <= s <= d_U, v_L, v_U
x_L <= x <= x_U z_L, z_U
The Lagragian for Ipopt is then
f(x) + y_c c(x) + y_d (d(x) - s) + v_L (d_L-s) + v_U (s-d_U) + z_L (x_L-x) + z_U (x-x_U)
and the gradient w.r.t. x is thus
f'(x) + y_c c'(x) + y_d d'(x) - z_L + z_U
The NLP that is used by most Ipopt interfaces is
min f(x) duals:
s.t. g_L <= g(x) <= g_U lambda
x_L <= x <= x_U z_L, z_U
The Gradient of the Lagrangian would be
f'(x) + lambda g'(x) - z_L + z_U
In your code, you have a wrong sign for z_L.
I'm trying to learn python - but new to OOP. I'd like to make the functions fA, fB, fC operate on the whole r-theta space at once, instead of one point at a time. My problem is the conditional (r<=1). The code below is quite ugly (!) but it works.
How can I make this more pythonesque? Thanks!
(in this simplified example, note the math for (r>1) diverges when r goes to zero)
from math import pi, sin, cos, exp
import numpy as np
import matplotlib.pyplot as plt
def fA(rr,th,a,b,c):
if (rr<=1):
fx = a * sin(th)
fy = b * rr * cos(th)
fz = c * rr
else:
fx = (a / rr) * sin(th)
fy = (b / rr) * cos(th)
fz = (c / rr)
return(fx,fy,fz)
def fB(rr,th,a,b,c):
if (rr<=1):
fx = b * sin(2.*th)
fy = a * rr * cos(2.*th)
fz = c * rr
else:
fx = (b / rr) * sin(2.*th)
fy = (a / rr) * cos(2.*th)
fz = c
return(fx,fy,fz)
def fC(rr,th,a,b,c):
if (rr<=1):
fx = exp(rr - 1.) * cos(th)
fy = exp(rr - 1.) * sin(th)
fz = c
else:
fx = exp(1. - rr) * cos(th)
fy = exp(1. - rr) * sin(th)
fz = c / rr
return(fx,fy,fz)
nx = 101
ny = 101
dx = 4. / (nx-1)
dy = 4. / (ny-1)
X = np.zeros((ny,nx))
Y = np.zeros((ny,nx))
for ix in range(nx):
for iy in range(ny):
X[iy,ix] = dx*(ix - (nx-1)/2)
Y[iy,ix] = dy*(iy - (ny-1)/2)
r = np.sqrt(X**2. + Y**2.)
theta = np.arctan2(Y,X)
Ax = np.zeros((ny,nx))
Ay = np.zeros((ny,nx))
Az = np.zeros((ny,nx))
Bx = np.zeros((ny,nx))
By = np.zeros((ny,nx))
Bz = np.zeros((ny,nx))
Cx = np.zeros((ny,nx))
Cy = np.zeros((ny,nx))
Cz = np.zeros((ny,nx))
for ix in range (nx):
for iy in range(ny):
Ax[iy,ix], Ay[iy,ix], Az[iy,ix] = fA(r[iy,ix], theta[iy,ix], 1.0, 1.0, 1.5)
Bx[iy,ix], By[iy,ix], Bz[iy,ix] = fB(r[iy,ix], theta[iy,ix], 1.5, 0.8, 1.0)
Cx[iy,ix], Cy[iy,ix], Cz[iy,ix] = fC(r[iy,ix], theta[iy,ix], 0.9, 1.1, 1.2)
plt.figure()
plt.subplot(3,3,1)
plt.imshow(Ax)
plt.colorbar()
plt.title('Ax')
plt.subplot(3,3,2)
plt.imshow(Ay)
plt.colorbar()
plt.title('Ay')
plt.subplot(3,3,3)
plt.imshow(Az)
plt.colorbar()
plt.title('Az')
plt.subplot(3,3,4)
plt.imshow(Bx)
plt.colorbar()
plt.title('Bx')
plt.subplot(3,3,5)
plt.imshow(By)
plt.colorbar()
plt.title('By')
plt.subplot(3,3,6)
plt.imshow(Bz)
plt.colorbar()
plt.title('Bz')
plt.subplot(3,3,7)
plt.imshow(Cx)
plt.colorbar()
plt.title('Cx')
plt.subplot(3,3,8)
plt.imshow(Cy)
plt.colorbar()
plt.title('Cy')
plt.subplot(3,3,9)
plt.imshow(Cz)
plt.colorbar()
plt.title('Cz')
plt.show()
Like #mdurant said np.where and np.meshgrid will be useful. Here, let me reorganize your code and provide another way to avoid Python looping by using numpy advanced indexing:
import sys
from math import pi, sin, cos, exp
import numpy as np
import matplotlib.pyplot as plt
def _generate_coordinate(nx, ny):
"""
Generate coordinate data points in a function to prevent namespace
pollution.
"""
dx = 4. / (nx-1)
dy = 4. / (ny-1)
X = np.zeros((ny,nx))
Y = np.zeros((ny,nx))
for ix in range(nx):
for iy in range(ny):
X[iy,ix] = dx*(ix - (nx-1)/2)
Y[iy,ix] = dy*(iy - (ny-1)/2)
return np.sqrt(X**2 + Y**2), np.arctan2(Y,X)
nx = ny = 101
r, theta = _generate_coordinate(101, 101)
def calculate_numpy():
# Helper methods for vector-based calculator.
def fA(rr, th, a, b, c):
# Calculate every value because mulplication doesn't give NaN.
arrx = a * np.sin(th)
arry = b * rr * np.cos(th)
arrz = c * rr
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = a / rr * np.sin(th)
arry[slct] = b / rr * np.cos(th)
arrz[slct] = c / rr
return arrx, arry, arrz
def fB(rr, th, a, b, c):
# Calculate every value because mulplication doesn't give NaN.
arrx = b * np.sin(2.*th)
arry = a * rr * np.cos(2.*th)
arrz = c * rr
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = b / rr * np.sin(2.*th)
arry[slct] = a / rr * np.cos(2.*th)
arrz[slct] = c
return arrx, arry, arrz
def fC(rr,th,a,b,c):
# Calculate every value because mulplication doesn't give NaN.
arrx = np.exp(rr-1) * np.cos(th)
arry = np.exp(rr-1) * np.sin(th)
arrz = np.empty_like(rr)
arrz.fill(c)
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = np.exp(1.-rr) * np.cos(th)
arry[slct] = np.exp(1.-rr) * np.sin(th)
arrz[slct] = c / rr
return arrx, arry, arrz
# Carry out calculation.
Ax, Ay, Az = fA(r, theta, 1.0, 1.0, 1.5)
Bx, By, Bz = fB(r, theta, 1.5, 0.8, 1.0)
Cx, Cy, Cz = fC(r, theta, 0.9, 1.1, 1.2)
return Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz
def calculate_loop():
# Helper methods for loop calculator.
def fA(rr,th,a,b,c):
if (rr<=1):
fx = a * sin(th)
fy = b * rr * cos(th)
fz = c * rr
else:
fx = (a / rr) * sin(th)
fy = (b / rr) * cos(th)
fz = (c / rr)
return(fx,fy,fz)
def fB(rr,th,a,b,c):
if (rr<=1):
fx = b * sin(2.*th)
fy = a * rr * cos(2.*th)
fz = c * rr
else:
fx = (b / rr) * sin(2.*th)
fy = (a / rr) * cos(2.*th)
fz = c
return(fx,fy,fz)
def fC(rr,th,a,b,c):
if (rr<=1):
fx = exp(rr - 1.) * cos(th)
fy = exp(rr - 1.) * sin(th)
fz = c
else:
fx = exp(1. - rr) * cos(th)
fy = exp(1. - rr) * sin(th)
fz = c / rr
return(fx,fy,fz)
# Create buffer arrays for loops.
Ax = np.zeros((ny,nx))
Ay = np.zeros((ny,nx))
Az = np.zeros((ny,nx))
Bx = np.zeros((ny,nx))
By = np.zeros((ny,nx))
Bz = np.zeros((ny,nx))
Cx = np.zeros((ny,nx))
Cy = np.zeros((ny,nx))
Cz = np.zeros((ny,nx))
# Carry out calculation with Python loops. This is slow.
for ix in range (nx):
for iy in range(ny):
Ax[iy,ix], Ay[iy,ix], Az[iy,ix] = fA(r[iy,ix], theta[iy,ix], 1.0, 1.0, 1.5)
Bx[iy,ix], By[iy,ix], Bz[iy,ix] = fB(r[iy,ix], theta[iy,ix], 1.5, 0.8, 1.0)
Cx[iy,ix], Cy[iy,ix], Cz[iy,ix] = fC(r[iy,ix], theta[iy,ix], 0.9, 1.1, 1.2)
return Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz
def main():
calculate = globals()["calculate_" + sys.argv[1]]
Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz = calculate()
plt.figure()
plt.subplot(3,3,1)
plt.imshow(Ax)
plt.colorbar()
plt.title('Ax')
plt.subplot(3,3,2)
plt.imshow(Ay)
plt.colorbar()
plt.title('Ay')
plt.subplot(3,3,3)
plt.imshow(Az)
plt.colorbar()
plt.title('Az')
plt.subplot(3,3,4)
plt.imshow(Bx)
plt.colorbar()
plt.title('Bx')
plt.subplot(3,3,5)
plt.imshow(By)
plt.colorbar()
plt.title('By')
plt.subplot(3,3,6)
plt.imshow(Bz)
plt.colorbar()
plt.title('Bz')
plt.subplot(3,3,7)
plt.imshow(Cx)
plt.colorbar()
plt.title('Cx')
plt.subplot(3,3,8)
plt.imshow(Cy)
plt.colorbar()
plt.title('Cy')
plt.subplot(3,3,9)
plt.imshow(Cz)
plt.colorbar()
plt.title('Cz')
plt.show()
if __name__ == '__main__':
main()
The function calculate_numpy() is where I demonstrate the advanced indexing. If you want to totally avoid duplicated calculation, you will need to create buffers like what you did in calculate_loop(). But I would say in terms of runtime, the duplication calculation is OK.
Let's say the program is saved in a file draw.py. We have both numpy ndarray and loop versions of the code, and can use timeit to benchmark them:
$ python -m timeit -s "import draw" "draw.calculate_loop()"
10 loops, best of 3: 95.2 msec per loop
$ python -m timeit -s "import draw" "draw.calculate_numpy()"
100 loops, best of 3: 2.11 msec per loop
As you can see, the numpy version is 45 times faster than your loop version. Most of the cases it's good enough.
Choosing one of your relations at random, you can use numpy.where instead of the if... semantics:
fx = where( rr<=1, exp(rr - 1.) * cos(th), exp(1. - rr) * cos(th))
This effectively does if/else for a set of arrays rather than one at a time individual numbers. You would then be able to do Ax, Ay, Az = fA(...) without the looping.
X and Y you can make using meshgrid or mgrid.
To not evaluate all elements, you could use slice notation
fx = empty_like(rr)
fx[rr<=1] = exp(rr[rr<=1] - 1.) * cos(th[rr<=1])
fx[rr>1] = exp(1. - rr[rr>1]) * cos(th[rr>1]))
My question is not how to filter an image using the laplacian of gaussian (basically using filter2D with the relevant kernel etc.).
What I want to know is how I generate the NxN kernel.
I'll give an example showing how I generated a [Winsize x WinSize] Gaussian kernel in openCV.
In Matlab:
gaussianKernel = fspecial('gaussian', WinSize, sigma);
In openCV:
cv::Mat gaussianKernel = cv::getGaussianKernel(WinSize, sigma, CV_64F);
cv::mulTransposed(gaussianKernel,gaussianKernel,false);
Where sigma and WinSize are predefined.
I want to do the same for a Laplacian of Gaussian.
In Matlab:
LoGKernel = fspecial('log', WinSize, sigma);
How do I get the exact kernel in openCV (exact up to negligible numerical differences)?
I'm working on a specific application where I need the actual kernel values and simply finding another way of implementing LoG filtering by approximating Difference of gaussians is not what I'm after.
Thanks!
You can generate it manually, using formula
LoG(x,y) = (1/(pi*sigma^4)) * (1 - (x^2+y^2)/(sigma^2))* (e ^ (- (x^2 + y^2) / 2sigma^2)
http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm
cv::Mat kernel(WinSize,WinSize,CV_64F);
int rows = kernel.rows;
int cols = kernel.cols;
double halfSize = (double) WinSize / 2.0;
for (size_t i=0; i<rows;i++)
for (size_t j=0; j<cols;j++)
{
double x = (double)j - halfSize;
double y = (double)i - halfSize;
kernel.at<double>(j,i) = (1.0 /(M_PI*pow(sigma,4))) * (1 - (x*x+y*y)/(sigma*sigma))* (pow(2.718281828, - (x*x + y*y) / 2*sigma*sigma));
}
If function above is not OK, you can simply rewrite matlab version of fspecial:
case 'log' % Laplacian of Gaussian
% first calculate Gaussian
siz = (p2-1)/2;
std2 = p3^2;
[x,y] = meshgrid(-siz(2):siz(2),-siz(1):siz(1));
arg = -(x.*x + y.*y)/(2*std2);
h = exp(arg);
h(h<eps*max(h(:))) = 0;
sumh = sum(h(:));
if sumh ~= 0,
h = h/sumh;
end;
% now calculate Laplacian
h1 = h.*(x.*x + y.*y - 2*std2)/(std2^2);
h = h1 - sum(h1(:))/prod(p2); % make the filter sum to zero
I want to thank old-ufo for nudging me in the correct direction.
I was hoping I won't have to reinvent the wheel by doing a quick matlab-->openCV conversion but guess this is the best solution I have for a quick solution.
NOTE - I did this for square kernels only (easy to modify otherwise, but I have no need for that so...).
Maybe this can be written in a more elegant form but is a quick job I did so I can carry on with more pressing matters.
From main function:
int WinSize(7); int sigma(1); // can be changed to other odd-sized WinSize and different sigma values
cv::Mat h = fspecialLoG(WinSize,sigma);
And the actual function is:
// return NxN (square kernel) of Laplacian of Gaussian as is returned by Matlab's: fspecial(Winsize,sigma)
cv::Mat fspecialLoG(int WinSize, double sigma){
// I wrote this only for square kernels as I have no need for kernels that aren't square
cv::Mat xx (WinSize,WinSize,CV_64F);
for (int i=0;i<WinSize;i++){
for (int j=0;j<WinSize;j++){
xx.at<double>(j,i) = (i-(WinSize-1)/2)*(i-(WinSize-1)/2);
}
}
cv::Mat yy;
cv::transpose(xx,yy);
cv::Mat arg = -(xx+yy)/(2*pow(sigma,2));
cv::Mat h (WinSize,WinSize,CV_64F);
for (int i=0;i<WinSize;i++){
for (int j=0;j<WinSize;j++){
h.at<double>(j,i) = pow(exp(1),(arg.at<double>(j,i)));
}
}
double minimalVal, maximalVal;
minMaxLoc(h, &minimalVal, &maximalVal);
cv::Mat tempMask = (h>DBL_EPSILON*maximalVal)/255;
tempMask.convertTo(tempMask,h.type());
cv::multiply(tempMask,h,h);
if (cv::sum(h)[0]!=0){h=h/cv::sum(h)[0];}
cv::Mat h1 = (xx+yy-2*(pow(sigma,2))/(pow(sigma,4));
cv::multiply(h,h1,h1);
h = h1 - cv::sum(h1)[0]/(WinSize*WinSize);
return h;
}
There is some difference between your function and the matlab version:
http://br1.einfach.org/tmp/log-matlab-vs-opencv.png.
Above is matlab fspecial('log', 31, 6) and below is the result of your function with the same parameters. Somehow the hat is more 'bent' - is this intended and what is the effect of this in later processing?
I can create a kernel very similar to the matlab one with these functions, which just directly reflect the LoG formula:
float LoG(int x, int y, float sigma) {
float xy = (pow(x, 2) + pow(y, 2)) / (2 * pow(sigma, 2));
return -1.0 / (M_PI * pow(sigma, 4)) * (1.0 - xy) * exp(-xy);
}
static Mat LOGkernel(int size, float sigma) {
Mat kernel(size, size, CV_32F);
int halfsize = size / 2;
for (int x = -halfsize; x <= halfsize; ++x) {
for (int y = -halfsize; y <= halfsize; ++y) {
kernel.at<float>(x+halfsize,y+halfsize) = LoG(x, y, sigma);
}
}
return kernel;
}
Here's a NumPy version that is directly translated from the fspecial function in MATLAB.
import numpy as np
import sys
def get_log_kernel(siz, std):
x = y = np.linspace(-siz, siz, 2*siz+1)
x, y = np.meshgrid(x, y)
arg = -(x**2 + y**2) / (2*std**2)
h = np.exp(arg)
h[h < sys.float_info.epsilon * h.max()] = 0
h = h/h.sum() if h.sum() != 0 else h
h1 = h*(x**2 + y**2 - 2*std**2) / (std**4)
return h1 - h1.mean()
The code below is the exact equivalent to fspecial('log', p2, p3):
def fspecial_log(p2, std):
siz = int((p2-1)/2)
x = y = np.linspace(-siz, siz, 2*siz+1)
x, y = np.meshgrid(x, y)
arg = -(x**2 + y**2) / (2*std**2)
h = np.exp(arg)
h[h < sys.float_info.epsilon * h.max()] = 0
h = h/h.sum() if h.sum() != 0 else h
h1 = h*(x**2 + y**2 - 2*std**2) / (std**4)
return h1 - h1.mean()
I wrote exact Implementation of Matlab fspecial function in OpenCV
function:
Mat C_fspecial_LOG(double* kernel_size,double sigma)
{
double size[2]={ (kernel_size[0]-1)/2 , (kernel_size[1]-1)/2};
double std = sigma;
const double eps = 2.2204e-16;
cv::Mat kernel(kernel_size[0],kernel_size[1],CV_64FC1,0.0);
int row=0,col=0;
for (double y = -size[0]; y <= size[0]; ++y,++row)
{
col=0;
for (double x = -size[1]; x <= size[1]; ++x,++col)
{
kernel.at<double>(row,col)=exp( -( pow(x,2) + pow(y,2) ) /(2*pow(std,2)));
}
}
double MaxValue;
cv::minMaxLoc(kernel,nullptr,&MaxValue,nullptr,nullptr);
Mat condition=~(kernel < eps*MaxValue)/255;
condition.convertTo(condition,CV_64FC1);
kernel = kernel.mul(condition);
cv::Scalar SUM = cv::sum(kernel);
if(SUM[0]!=0)
{
kernel /= SUM[0];
}
return kernel;
}
usage of this function :
double kernel_size[2] = {4,4}; // kernel size set to 4x4
double sigma = 2.1;
Mat kernel = C_fspecial_LOG(kernel_size,sigma);
compare OpenCV result with Matlab:
opencv result:
[0.04918466596701741, 0.06170341496034986, 0.06170341496034986, 0.04918466596701741;
0.06170341496034986, 0.07740850411228289, 0.07740850411228289, 0.06170341496034986;
0.06170341496034986, 0.07740850411228289, 0.07740850411228289, 0.06170341496034986;
0.04918466596701741, 0.06170341496034986, 0.06170341496034986, 0.04918466596701741]
Matlab result for fspecial('gaussian', 4, 2.1) :
0.0492 0.0617 0.0617 0.0492
0.0617 0.0774 0.0774 0.0617
0.0617 0.0774 0.0774 0.0617
0.0492 0.0617 0.0617 0.0492
Just for the sake of reference, here is a Python implementation which creates the LoG filter kernel to detect blobs of a pre-defined radius in pixels.
def create_log_filter_kernel(r_in_px: float):
"""
Creates a LoG filter-kernel to detect blobs of a given radius r_in_px.
\[
LoG(x,y) = \frac{-1}{\pi\sigma^4}\left(1 - \frac{x^2 + y^2}{2\sigma^2}\right)e^{\frac{-(x^2+y^2)}{2\sigma^2}}
\]
Look for maxima if blob is black, minima if blob is white.
:param r_in_px:
:return: filter kernel
"""
# sigma from radius: LoG has zero-crossing at $1 - \frac{x^2 + y^2}{2\sigma^2} = 0$
# i.e. r^2 = 2\sigma^2$ and thus $sigma = r / \sqrt{2}$
sigma = r_in_px/np.sqrt(2)
# ksize such that filter covers $3\sigma$
ksize = int(np.round(sigma*3))*2 + 1
# setup filter
xgv = np.arange(0, ksize) - ksize / 2
ygv = np.arange(0, ksize) - ksize / 2
x, y = np.meshgrid(xgv, ygv)
kernel = -1 / (np.pi * sigma**4) * (1 - (x**2 + y**2) / (2*sigma**2)) * np.exp(-(x**2 + y**2) / (2 * sigma**2))
#normalize to sum zero (does not change zero crossing, I tried it out for r < 100)
kernel -= np.sum(kernel) / ksize**2
#this is important: normalize such that positive/negative parts are comparable over different scales
kernel /= np.sum(kernel[kernel>0])
return kernel
I am trying to integrate a second order differential equation using 'scipy.integrate.odeint'. My eqution is as follows
m*x[i]''+x[i]'= K/N*sum(j=0 to N)of sin(x[j]-x[i])
which I have converted into two first order ODEs as followed. In the below code, yinit is array of the initial values x(0) and x'(0). My question is what should be the values of x(0) and x'(0) ?
x'[i]=y[i]
y'[i]=(-y[i]+K/N*sum(j=0 to N)of sin(x[j]-x[i]))/m
from numpy import *
from scipy.integrate import odeint
N = 50
def f(theta, t):
global N
x, y = theta
m = 0.95
K = 1.0
fx = zeros(N, float)
for i in range(N):
s = 0.0
for j in range(i+1,N):
s = s + sin(x[j] - x[i])
fx[i] = (-y[i] + (K*s)/N)/m
return array([y, fx])
t = linspace(0, 10, 100, endpoint=False)
Uniformly generating random number
theta = random.uniform(-180, 180, N)
Integrating function f using odeint
yinit = array([x(0), x'(0)])
y = odeint(f, yinit, t)[:,0]
print (y)
You can choose as initial condition whatever you want.
In your case, you decided to use a random initial condition for x for all the oscillators. You can use a random initial condition for 'y' as well I guess, as I did below.
There were a few errors in the above code, mostly on how to unpack x,y from theta and how to repack them at the end (see concatenate below in the corrected code). See also the concatenate for yinit.
The rest are stylish/minor changes.
from numpy import concatenate, linspace, random, mod, zeros, sin
from scipy.integrate import odeint
Nosc = 20
assert mod(Nosc, 2) == 0
def f(theta, _):
N = theta.size / 2
x, y = theta[:N], theta[N:]
m = 0.95
K = 1.0
fx = zeros(N, float)
for i in range(N):
s = 0.0
for j in range(i + 1, N):
s = s + sin(x[j] - x[i])
fx[i] = (-y[i] + (K * s) / N) / m
return concatenate(([y, fx]))
t = linspace(0, 10, 50, endpoint=False)
theta = random.uniform(-180, 180, Nosc)
theta2 = random.uniform(-180, 180, Nosc) #added initial condition for the velocities of the oscillators
yinit = concatenate((theta, theta2))
res = odeint(f, yinit, t)
X = res[:, :Nosc].T
Y = res[:, Nosc:].T
To plot the time evolution of the system, you can use something like
import matplotlib.pylab as plt
fig, ax = plt.subplots()
for displacement in X:
ax.plot(t, displacement)
ax.set_xlabel('t')
ax.set_ylabel('x')
fig.show()
What are you modelling? At first the eq. looked a bit like kuramoto oscillators, but then I noticed you also have a x[i]'' term.
Notice how in your model, as you do not have a spring term in the equation, like a term x(t) at the LHS, the value of x converges to an arbitrary value:
Why do below two versions of a same problem give different result y_phi, while all parameters are same and random values are seeded with same value in both versions ?
I know Version_1 gives correct result while Version_2 gives false result, why is that so?
Where am I making mistake in Version_2 ?
Version_1:
from numpy import *
import random
from scipy.integrate import odeint
def f(phi, t, alpha):
v_phi = zeros(x*y, float)
for n in range(x*y):
cmean = cos(phi[n])
smean = sin(phi[n])
v_phi[n] = smean*cos(phi[n]+alpha)-cmean*sin(phi[n]+alpha)
return v_phi
x = 5
y = 5
N = x*y
PI = pi
alpha = 0.2*PI
random.seed(1010)
phi = zeros(x*y, float)
for i in range(x*y):
phi[i] = random.uniform(0.0, 2*PI)
t = arange(0.0, 100.0, 0.1)
y = odeint(f, phi, t, args=(alpha,))
y_phi = [y[len(t)-1, i] for i in range(N)]
print y_phi
Version_2:
def f(phi, t, alpha, cmean, smean):
v_phi = zeros(x*y, float)
for n in range(x*y):
v_phi[n] = smean[n]*cos(phi[n]+alpha)-cmean[n]*sin(phi[n]+alpha)
return v_phi
x = 5
y = 5
N = x*y
PI = pi
alpha = 0.2*PI
random.seed(1010)
phi = zeros(x*y, float)
for i in range(x*y):
phi[i] = random.uniform(0.0, 2*PI)
t = arange(0.0, 100.0, 0.1)
cmean = []
smean = []
for l in range(x*y):
cmean.append(cos(phi[l]))
smean.append(sin(phi[l]))
y = odeint(f, phi, t, args=(alpha, cmean, smean,))
y_phi = [y[len(t)-1, i] for i in range(N)]
print y_phi
In the first case smean = cos(phi(t)[n]), it depends on the current value of phi, but in the second smean = cos(phi(0)[n]) and depends only on the initial value. (And similarly for cmean).
Btw, you could have found this issue also using http://en.wikipedia.org/wiki/Rubber_duck_debugging