Generalized Distance Transform in Python - python

I'm currently trying to implement the GDT described by Felzenszwalb and Huttenlocher (http://www.cs.cornell.edu/~dph/papers/dt.pdf) inside of Python for an image processing algorithm. However I used the algorithm described in the paper they published a few years back but got faulty results. I found a C# implementation here: https://dsp.stackexchange.com/questions/227/fastest-available-algorithm-for-distance-transform/29727?noredirect=1#comment55866_29727
And converted it to Python (which is pretty much the same I had before).
This is my code:
def of_column(dataInput):
output = zeros(dataInput.shape)
n = len(dataInput)
k = 0
v = zeros((n,))
z = zeros((n + 1,))
v[0] = 0
z[0] = -inf
z[1] = +inf
s = 0
for q in range(1, n):
while True:
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
if s <= z[k]:
k -= 1
else:
break
k += 1
v[k] = q
z[k] = s
z[k + 1] = +inf
k = 0
for q in range(n):
while z[k + 1] < q:
k += 1
output[q] = ((q - v[k]) * (q - v[k]) + dataInput[v[k]])
return output
I still can't find my error. When giving the algorithm a binary (boolean) numpy array it just returns the array itself not the Distance Transform. Why is this not working in Python?

I got it working after hours and hours. The answer given in the link above implementing the code in C# suggests putting up the "white" areas to a very large number. My dataInput array was a boolean array (0, 1). I replaced all 1s with 2^32 and it works just fine. The higher the number the more blurry it gets. The lower the more similar to the source it gets.

I would like to add the function for 2D that works with the 1D function described previously:
###############################################################################
# distance transform of 1d function using squared distance
###############################################################################
def dt_1d(dataInput, n):
output = np.zeros(dataInput.shape)
k = 0
v = np.zeros((n,))
z = np.zeros((n + 1,))
v[0] = 0
z[0] = -np.inf
z[1] = +np.inf
for q in range(1, n):
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
while s <= z[k]:
k -= 1
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
k += 1
v[k] = q
z[k] = s
z[k + 1] = +np.inf
k = 0
for q in range(n):
while z[k + 1] < q:
k += 1
value = ((q - v[k]) * (q - v[k]) + dataInput[v[k]])
if value > 255: value = 255
if value < 0: value = 0
output[q] = value
print output
return output
###############################################################################
# distance transform of 2d function using squared distance
###############################################################################
def dt_2d(dataInput):
height, width = dataInput.shape
f = np.zeros(max(height, width))
# transform along columns
for x in range(width):
f = dataInput[:,x]
dataInput[:,x] = dt_1d(f, height)
# transform along rows
for y in range(height):
f = dataInput[y,:]
dataInput[y,:] = dt_1d(f, width)
return dataInput
I hope it helps.

Related

Looking for pi until percent error is below 1e-2

I'm using this formula that involves factorials and double factorials to find value of pi until percent error is below 1e-2. For some reason the while loop that's calculating pi until that PE is low enough doesn't stop (at least that's what I think is happening).
import numpy as np
k = 1
pe = 100
def doublefactorial(n):
if n == 0 or n == 1:
return 1
return n * doublefactorial(n - 2)
while pe >= 1e-2:
f = 1
for i in range(1, k + 1):
f = f * i
D = doublefactorial(2 * k + 1)
r = f / D
pe = abs(((r - np.pi) / np.pi) * 100)
k = k + 1
print("pi= ", r, "PE= ", pe)
There were a couple of things that could be improved in your code, below is a commented version with said improvements:
That for you are using to calculate k! was hard to understand, so I used python's factorial function and changed your f/D to N/D, keeping the fraction form you used.
This is a summation, so don't forget to update r's value every iteration.
The output of the formula is Pi / 2, so you can't compare it directly with np.pi.
You start with k=1, but your formula states k=0.
Also I moved the print inside the loop so you can see the values updating on each iteration.
import numpy as np
import math
k = 0
r = 0
pe = 100
def doublefactorial(n):
if n == 0 or n == 1:
return 1
return n * doublefactorial(n - 2)
while pe >= 1e-2:
# using math.factorial for easier to read code
N = math.factorial(k)
D = doublefactorial(2 * k + 1)
# our approximation = numerator / dividend
# update r's value (this is equivalent to r = r + N/D)
r += N / D
# don't forget the formula gives Pi/2 so to compare and print we should double it...
pi_approx = 2 * r
pe = abs(((pi_approx - np.pi) / np.pi) * 100)
k = k + 1
print("pi= ", pi_approx, "PE= ", pe)

Python simple Convolution in numpy

I have written this simple convolution function in numpy. But the final array values are all still zero.
Please help me correct this function.
def convolve(a_prev, w, b):
pad = 0
stride = 1
s1 = a_prev.shape
s2 = w.shape
f = s2[1]
m = s1[0]
n_c = s2[0]
n_h = int((s1[1] - f + 2 * pad) / stride) + 1
n_w = int((s1[2] - f + 2 * pad) / stride) + 1
a = np.zeros((m,n_h,n_w,n_c), dtype=np.float32)
for n in range(m):
for z in range(n_c):
y = 0
x = 0
while ((y+f) <= n_h):
# Edit: forget to inialize the x = 0
while ((x+f) <= n_w):
#a[n,y,x,z] = np.sum(a_prev[n,y:y+f,x:x+f]*w[z]) + b[z,0]
a[n,y,x,z] = np.sum(np.multiply(a_prev[n,y:y+f,x:x+f],w[z])) + b[z,0]
x += stride
y += stride
print(a[0,85,:,3])
return a
shape of a_prev is [num_exmamples,height, width, 3] and w is [num_filters,3,3,3]
I found the reason, why it was not working, i make a programming error and forget to initialize the x = 0 before while loop.
Its working fine now.
Below is the correct function.
def convolve(a_prev, kernel, b, pad = 0, stride = 1):
m = a_prev.shape[0]
prev_h = a_prev.shape[1]
prev_w = a_prev.shape[2]
f = kernel.shape[1]
n_c = kernel.shape[0]
new_h = int((prev_h - f + 2 * pad) / stride) + 1
new_w = int((prev_w - f + 2 * pad) / stride) + 1
az = np.zeros((m,new_h,new_w,n_c), dtype=np.float32)
for n in range(m):
for z in range(n_c):
y = 0
while (y+f) <= prev_h:
x = 0
while (x+f) <= prev_w:
az[n,y,x,z] = np.sum(a_prev[n,y:y+f,x:x+f]*kernel[z]) + b[z,0]
x += stride
y += stride
return az
There is an easier way to do convolution without using the previous input as a function input.
import numpy as np
def convolution(x, h):
# x and h are numpy arrays
M, N = np.size(x), np.size(h)
y = np.zeros(M+N-1)
# Initialise y with the length of the output signal
for m in np.arange(M):
for n in np.arange(N):
y[m+n] += x[m]*h[n]
return y
This function uses the basic definition of convolution for discrete signals

Taylor Series for sine using functions

I've created a fatorial function that would help me calculate the taylor expansion of sine. There are no evident mistakes in my code, but the returned value is wrong. That's my code:
PI = 3.14159265358979323846
def fatorial(n):
fatorial = 1
for i in range(1,n+1,1):
fatorial = fatorial * i
return fatorial
def seno(theta):
n = 1
k = 3
eps = 10**-10
theta = (theta*PI)/180
x = ((-1)**n)*((theta)**k)
y = fatorial(k)
while x/y > eps or x/y < -eps:
theta = theta + (x/y)
n = n + 1
k = k + 2
x = ((-1)**n) * ((theta)**k)
y = fatorial(k)
return theta
You are summing theta in the while-loop and therefore using an adjusted angle for the next elements of the Taylor series. Just add a thetas (for the sum) like so (I have taken the liberty to add some performance improvements, no need to recalculate the full factorial, also calculated first elements explicitly and changed the limit check to avoid recalculations of x/y):
import math
PI = 3.14159265358979323846
def fatorial(n):
fatorial = 1
for i in range(1,n+1,1):
fatorial = fatorial * i
return fatorial
def seno(theta):
n = 1
k = 3
#eps = 10**-10
theta = (theta*PI)/180
thetas = theta # <- added this
x = -theta*theta*theta
y = 6
#while x/y > eps or x/y < -eps:
while k < 14:
thetas = thetas + (x/y) # sum thetas
n = n + 1
k = k + 2
#x = ((-1)**n) * ((theta)**k)
x = ((-1)**(n%2)) * ((theta)**k) # but use the original value for the series
#y = fatorial(k)
y *= k * (k-1)
return thetas # return the sum
if __name__ == '__main__':
print(seno(80), math.sin(8*PI/18))
this results in
0.984807753125684 0.984807753012208

Python .append seems to run forever and the 'uniform' value seems not too random (making Poisson sphere distribution in Python)

I am now trying to calculate the poisson sphere distribution(a 3D version of the poisson disk) using python and then plug in the result to POV-RAY so that I can generate some random distributed packing rocks.
I am following these two links:
[https://github.com/CodingTrain/Rainbow-Code/blob/master/CodingChallenges/CC_33_poisson_disc/sketch.js#L13]
[https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf]tl;dr
0.Create an n-dimensional grid array and cell size = r/sqrt(n) where r is the minimum distance between each sphere. All arrays are set to be default -1 which stands for 'without point'
1.Create an initial sample. (it should be placed randomly but I choose to put it in the middle). Put it in the grid array. Also, intialize an active array. Put the initial sample in the active array.
2.While the active list is not empty, pick a random index. Generate points near it and make sure the points are not overlapping with nearby points(only test with the nearby arrays). If no sample can be created near the 'random index', kick the 'random index' out. Loop the process.
And here is my code:
import math
import numpy
from random import uniform
import random
from math import floor
r = 1
k = 30
grid = []
w = r / math.sqrt(2)
active = []
width = 100
height = 100
depth = 100
cols = floor(width / w)
rows = floor(height / w)
deps = floor(depth / w)
default = numpy.array((-1,-1,-1))
for i in range(cols * rows * deps):
grid.append(default)
x = width / 2
y = height / 2
z = depth / 2
i = floor(x / w)
j = floor(y / w)
k = floor(z / w)
pos = numpy.array((x,y,z))
grid[i + cols * (j + rows * k)] = pos
active.append(pos)
while (len(active) > 0) and (len(grid[grid == -1]) > 0):
randIndex = floor(uniform(0, len(active)))
pos = active[randIndex]
found = False
for n in range(k):
m1 = uniform(-2 * r, 2 * r)
m2 = uniform(-2 * r, 2 * r)
m3 = uniform(-2 * r, 2 * r)
m = numpy.array((m1,m2,m3))
sample = numpy.add(pos, m)
col = floor(sample[0] / w)
row = floor(sample[1] / w)
dep = floor(sample[2] / w)
if (col > -1 and row > -1 and dep > -1 and col < cols and row < rows and dep < deps and numpy.all([grid[col + cols * (row + rows * dep)],default])==True):
ok = True
for i in range(-1,2):
for j in range(-1, 2):
for k in range(-1, 2):
index = (col + i) + cols * ((row + j) + rows * (dep + k))
if col + i > -1 and row + j > -1 and dep + k > -1 and col + i < cols and row + j < rows and dep + k < deps:
neighbor = grid[index]
if numpy.all([neighbor, default]) == False:
d = numpy.linalg.norm(sample - neighbor)
if (d < r):
ok = False
if ok == True:
found = True
grid[col + cols * (row + rows * dep)] = sample
active.append(sample)
if found == False:
del active[randIndex]
print(len(active))
for printout in range(len(grid)):
print("<" + str(active[printout][0]) + "," + str(active[printout][1]) + "," + str(active[printout][2]) + ">")
print(len(grid))
My code seems to run forever and do not obey my condition(distance of two spheres must be larger than 2 * radius) as shown in the visualization by POV-RAY.(picture in comment)
Therefore I tried to add a print(len(active)) in the last of the while loop.
Surprisingly, I think I discovered the bug as the length of the active list just keep increasing! (It is supposed to be the same length as the grid) I think the problem is caused by the active.append(), but I can't figure out where is the problem as the code is literally the 90% the same as the one made by Mr.Shiffman.
I don't want to free ride this but I have already checked again and again while correcting again and again for this code :(. Still, I don't know where the bug is. (why do the active[] keep appending!?)
Thank you for the precious time.

Python implementation of gradient descent (Machine Learning)

I have tried to implement gradient descent here in python but the cost J just seems to be increasing irrespective of lambda ans alpha value, i am unable to figure out what the issue over here is. It'll be great if someone can help me out with this. The input is a matrix Y and R with same dimensions. Y is a matrix of movies x users and R is just to say if a user has rated a movie.
#Recommender system ML
import numpy
import scipy.io
def gradientDescent(y,r):
(nm,nu) = numpy.shape(y)
x = numpy.mat(numpy.random.randn(nm,10))
theta = numpy.mat(numpy.random.randn(nu,10))
for i in range(1,10):
(x,theta) = costFunc(x,theta,y,r)
def costFunc(x,theta,y,r):
X_tmp = numpy.power(x , 2)
Theta_tmp = numpy.power(theta , 2)
lmbda = 0.1
reg = ((lmbda/2) * numpy.sum(Theta_tmp))+ ((lmbda/2)*numpy.sum(X_tmp))
ans = numpy.multiply(numpy.power(((theta * x.T).T - y),2) , r)
res = (0.5 * numpy.sum(ans))+reg
print "J:",res
print "reg:",reg
(nm,nu) = numpy.shape(y)
X_grad = numpy.mat(numpy.zeros((nm,10)));
Theta_grad = numpy.mat(numpy.zeros((nu,10)));
alpha = 0.1
# [m f] = size(X);
(m,f) = numpy.shape(x);
for i in range(0,m):
for k in range(0,f):
tmp = 0
# X_grad(i,k) += (((theta * x'(:,i)) - y(i,:)').*r(i,:)')' * theta(:,k);
tmp += ((numpy.multiply(((theta * x.T[:,i]) - y[i,:].T),r[i,:].T)).T) * theta[:,k];
tmp += (lmbda*x[i,k]);
X_grad[i,k] -= (alpha*tmp)
# X_grad(i,k) += (lambda*X(i,k));
# [m f] = size(Theta);
(m,f) = numpy.shape(theta);
for i in range(0,m):
for k in range(0,f):
tmp = 0
# Theta_grad(i,k) += (((theta(i,:) * x') - y(:,i)').*r(:,i)') * x(:,k);
tmp += (numpy.multiply(((theta[i,:] * x.T) - y[:,i].T),r[:,i].T)) * x[:,k];
tmp += (lmbda*theta[i,k]);
Theta_grad[i,k] -= (alpha*tmp)
# Theta_grad(i,k) += (lambda*Theta(i,k));
return(X_grad,Theta_grad)
def main():
mat1 = scipy.io.loadmat("C:\Users\ROHIT\Machine Learning\Coursera\mlclass-ex8\ex8_movies.mat")
Y = mat1['Y']
R = mat1['R']
r = numpy.mat(R)
y = numpy.mat(Y)
gradientDescent(y,r)
#if __init__ == '__main__':
main()
I did not check the whole code logic, but assuming it is correct, your costfunc is supposed to return gradient of the cost function, and in these lines:
for i in range(1,10):
(x,theta) = costFunc(x,theta,y,r)
you are overwriting the last values of x and theta with its gradient, while gradient is the measure of change, so you should move in the opposite direction (substract the gradient instead of overwriting the values):
for i in range(1,10):
(x,theta) -= costFunc(x,theta,y,r)
But it seems that you already assign the minus sign to the gradient in your costfunc so you should add this value instead
for i in range(1,10):
(x,theta) += costFunc(x,theta,y,r)

Categories

Resources