I am currently stumped by an artefact in my code. It appears to produce very sharp points in a grid pattern that have a noticeable difference in value to their neighbours.
I am following the blog post at http://www.bluh.org/code-the-diamond-square-algorithm/ and converting from whichever language they are using (assuming either C# or Java), and have double-checked that what I am doing should match.
Is there any chance that someone could have a browse over this, and see what I'm doing wrong? I've stepped through it at smaller levels, and stopped it on specific iterations of the algorithm (by unrolling the top loop, and explicitly calling the algorithm a set number of times) and everything seems to work until we get to the very last set of points/pixels.
I use a class (called Matrix) to access the list, and wrap any out of bounds values.
The code for the algorithm is as follows:
class World :
def genWorld (self, numcells, cellsize, seed):
random.seed(seed)
self.dims = numcells*cellsize
self.seed = seed
self.cells = Matrix(self.dims, self.dims)
# set the cells at cellsize intervals
half = cellsize/2
for y in range(0, self.dims, cellsize):
for x in range(0, self.dims, cellsize):
self.cells[x,y] = random.random()
scale = 1.0
samplesize = cellsize
while samplesize > 1:
self._diamondSquare(samplesize, scale)
scale *= 0.8
samplesize = int(samplesize/2)
# I need to sort out the problem with the diamond-square algo that causes it to make the weird gridding pattern
def _sampleSquare(self, x, y, size, value):
half = size/2
a = self.cells[x-half, y-half]
b = self.cells[x+half, y-half]
c = self.cells[x-half, y+half]
d = self.cells[x+half, y+half]
res = min(((a+b+c+d+value)/5.0), 1.0)
self.cells[x, y] = res
def _sampleDiamond(self, x, y, size, value):
half = size/2
a = self.cells[x+half, y]
b = self.cells[x-half, y]
c = self.cells[x, y+half]
d = self.cells[x, y-half]
res = min(((a+b+c+d+value)/5.0), 1.0)
self.cells[x, y] = res
def _diamondSquare(self, stepsize, scale):
half = int(stepsize/2)
for y in range(half, self.dims+half, stepsize):
for x in range(half, self.dims+half, stepsize):
self._sampleSquare(x, y, stepsize, random.random()*scale)
for y in range(0, self.dims, stepsize):
for x in range(0, self.dims, stepsize):
self._sampleDiamond(x+half, y, stepsize, random.random()*scale)
self._sampleDiamond(x, y+half, stepsize, random.random()*scale)
and is called with:
w = World()
w.genWorld(16, 16, 1) # a 256x256 square world, since the numcells is multiplied by the cellsize to give us the length of ONE side of the resulting grid
then I save to file to check the result:
file = io.open("sample.raw",'wb')
arr = [int(i * 255) for i in w.cells.cells] # w.cells.cells should not have a value >= 1.0, so what's going on?
ind = 0
for a in arr:
if a > 255:
print ("arr["+str(ind)+"] ::= "+str(a))
ind += 1
file.write(bytearray(arr))
file.close()
which gives the result:
EDIT: Okay, so it appears that I managed to get it working. I swapped from using functions for working out the diamond and square steps to doing it all in the _diamondSquare() function, but this wasn't the only thing. I also found out that random.random() provides values in the range [0.0 ->1.0), when I was expecting values in the range [-1.0 -> 1.0). After I corrected this, everything started working properly, which was a relief.
Thanks for the advice everyone, here's the working code in case anyone else is struggling with something similar:
Random Function
# since random.random() gives a value in the range [0.0 -> 1.0), I need to change it to [-1.0 -> 1.0)
def rand():
mag = random.random()
sign = random.random()
if sign >=0.5:
return mag
return mag * -1.0
Matrix class
class Matrix:
def __init__(self, width, height):
self.cells = [0 for i in range(width*height)]
self.width = width
self.height = height
self.max_elems = width*height
def _getsingleindex(self, ind):
if ind < 0:
ind *= -1
while ind >= self.max_elems:
ind -= self.max_elems
return ind
def _getmultiindex(self, xind, yind):
if xind < 0:
xind *= -1
if yind < 0:
yind *= -1
while xind >= self.width:
xind -= self.width
while yind >= self.height:
yind -= self.height
return xind + (yind*self.height)
def __getitem__(self, inds):
# test that index is an integer, or two integers, and throw an indexException if not
if hasattr(inds, "__len__"):
if len(inds) > 1:
return self.cells[self._getmultiindex(int(inds[0]), int(inds[1]))]
return self.cells[self._getsingleindex(int(inds))]
def __setitem__(self, inds, object):
# test that index is an integer, or two integers, and throw an indexException if not
if hasattr(inds, "__len__"):
if len(inds) > 1:
self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))] = object
return self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))]
self.cells[self._getsingleindex(int(inds))] = object
return self.cells[self._getsingleindex(int(inds))]
def __len__(self):
return len(self.cells)
The Actual Diamond-Square Generation
# performs the actual 2D generation
class World:
def genWorld (self, numcells, cellsize, seed, scale = 1.0):
random.seed(seed)
self.dims = numcells*cellsize
self.seed = seed
self.cells = Matrix(self.dims, self.dims)
mountains = Matrix(self.dims, self.dims)
# set the cells at cellsize intervals
for y in range(0, self.dims, cellsize):
for x in range(0, self.dims, cellsize):
# this is the default, sets the heights randomly
self.cells[x,y] = random.random()
while cellsize > 1:
self._diamondSquare(cellsize, scale)
scale *= 0.5
cellsize = int(cellsize/2)
for i in range(len(mountains)):
self.cells[i] = self.cells[i]*0.4 + (mountains[i]*mountains[i])*0.6
def _diamondSquare(self, stepsize, scale):
half = int(stepsize/2)
# diamond part
for y in range(half, self.dims+half, stepsize):
for x in range(half, self.dims+half, stepsize):
self.cells[x, y] = ((self.cells[x-half, y-half] + self.cells[x+half, y-half] + self.cells[x-half, y+half] + self.cells[x+half, y+half])/4.0) + (rand()*scale)
# square part
for y in range(0, self.dims, stepsize):
for x in range(0, self.dims, stepsize):
self.cells[x+half,y] = ((self.cells[x+half+half, y] + self.cells[x+half-half, y] + self.cells[x+half, y+half] + self.cells[x+half, y-half])/4.0)+(rand()*scale)
self.cells[x,y+half] = ((self.cells[x+half, y+half] + self.cells[x-half, y+half] + self.cells[x, y+half+half] + self.cells[x, y+half-half])/4.0)+(rand()*scale)
Main Function (added for completeness)
# a simple main function that uses World to create a 2D array of diamond-square values, then writes it to a file
def main():
w = World()
w.genWorld(20, 16, 1)
mi = min(w.cells.cells)
ma = max(w.cells.cells) - mi
# save the resulting matrix to an image file
file = io.open("sample.raw",'wb')
maxed = [(i-mi)/ma for i in w.cells.cells]
arr = [int(i * 255) for i in maxed]
file.write(bytearray(arr))
file.close()
Related
I am currently trying to make a game of life using tkinter.
One issue though: the rectangles I create won't respond to the itemconfigure method called to change their fill color. Once the tk window opened, there seems to be no way to change their color... Here is the code used: (variable names are in french, my apologies)
from tkinter import *
from numpy import *
Res = (1000, 1000)
dim = (50, 50)
BordABord = False
F = Tk()
C = Canvas(F, height = Res[1], width = Res[0])
L = ndarray(dim, dtype = bool)
Grille = ndarray(dim)
lar = []
for i in range(2):
lar.append(Res[i] // dim[i])
for i in range(dim[0]):
x = i * lar[0]
for j in range(dim[1]):
y = j * lar[1]
Grille[i, j] = C.create_rectangle(x, y, x + lar[0], y + lar[1], fill = 'white')
L[i, j] = False
def rgbTraducteur(rgb):
return "#%02x%02x%02x" % rgb
def process():
global L
global Grille
global dim
global C
for i in range(dim[0]):
for j in range(dim[1]):
if L[i, j]:
print('processssss')
C.itemconfigure(Grille[i, j], fill = 'black')
def clic(event):
print('clic')
global L
global Res
global dim
x = int(dim[0] * event.x / Res[0])
y = int(dim[1] * event.y / Res[1])
print(x, y)
L[x, y] = not(L[x, y])
process()
def pas(event = 0):
global L
global BordABord
global dim
N = L
for i in range(dim[0]):
for j in range(dim[1]):
compte = 0
for k in range(-1, 2):
x = i + k
if BordABord or x // dim[0] == 0:
x %= dim[0]
for l in range(-1, 2):
if l != 0 and k != 0:
y = j + l
if BordABord or y // dim[1] == 0:
y %= dim[1]
compte += L[x, y]
if L[i, j]:
N[i, j] = (compte - 2) // 2 == 0
else:
N[i, j] = compte == 3
L = N
process()
F.bind('<Button-1>', clic)
F.bind('<Return>', pas)
C.pack()
F.mainloop()
it is, of course, not optimised at all, and all rectangles have been set to turn black whenever process() is called as a test.
Canvas items are given an integer identifier. You must use the integer to refer to the item. A floating point number such as 1.0 does not refer to the item with an integer identifier of 1.
The problem in your code is that Grille is an array of floating point numbers. When you do Grille[i, j] = C.create_rectangle(...), create_rectangle will return an integer but it gets stored as floating point. Thus, your call to itemconfigure tries to change something with the floating point number 1.0 rather than the integer id of 1. If you pass something that is not an integer to itemconfigure the canvas assumes it is a tag. Since no elements have the tag 1.0, no elements are configured.
If you change the array to hold integers so that the numbers aren't converted, itemconfigure will work fine.
Grille = ndarray(dim, dtype=int)
from PIL import Image
import numpy as np
import math
class Fractal(object):
def __init__(self, resolution=(720,720), x_range=(-2.0,2.0), y_range=(-2.0,2.0), maxIterations=255, zoom=0, zoomRate=0):
self.resolution = resolution
self.x_range = x_range
self.y_range = y_range
self.maxIterations = maxIterations
self.zoom = zoom
self.zoomRate = zoomRate
def computePixel(self, x, y):
z = complex(0.0,0.0)
c = complex(x,y)
iterations = 0
while iterations < self.maxIterations or abs(z)<2:
z = z*z + c
iterations += 1
# pixelHue = (360/self.maxIterations)*iterations
# RGB = hsv_to_rgb(pixelHue, 0.0, 0.0)
# return RGB
return iterations
def generateFrame(self):
#x_max, x_min, y_max, y_min = self.zoom()
x_max, x_min, y_max, y_min = (self.x_range[1],self.x_range[0],self.y_range[1],self.y_range[0])
x_increment = (x_max - x_min)/self.resolution[0]
print(x_increment)
y_increment = (y_max - y_min)/self.resolution[1]
print(y_increment)
frame = []
yPixels = []
for x in np.arange(x_min, x_max, x_increment):
for y in np.arange(y_min, y_max, y_increment):
x,y = float(x), float(y)
iterations = self.computePixel(x,y)
print(x,y,iterations)
# pixel_RGB= self.computePixel(x,y)
# yPixels.append(pixel_RGB)
# frame.append(yPixels)
# return frame
def zoom(self):
'''this is the change that will happen in one second'''
x_max = self.x_range[1]-(self.zoomRate/2)
x_min = self.x_range[0]+(self.zoomRate/2)
y_max = self.y_range[1]-(self.zoomRate/2)
y_min = self.y_range[0]+(self.zoomRate/2)
return (x_max, x_min, y_max, y_min)
def sweep(self):
for x in np.arange(self.size[0]):
for y in np.arange(self.size[1]):
pass
def hsv_to_rgb(h, s, v):
if s == 0.0: return (v, v, v)
i = int(h*6.) # XXX assume int() truncates!
f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
if i == 0: return (v, t, p)
if i == 1: return (q, v, p)
if i == 2: return (p, v, t)
if i == 3: return (p, q, v)
if i == 4: return (t, p, v)
if i == 5: return (v, p, q)
f = Fractal()
f.generateFrame()
Currently, I'm only trying to display the first frame of the GIF, i.e. the non-zoomed-into Mandelbrot set. However, when I try to iterate through all the pixel values the iteration stops at x=-1.8611111111111116 and y=-0.005555555555562641
I'm guessing this is because of some overflow error occurring when y is supposed to be zero, but I don't know how to solve this.
Here's a final screenshot of the command line where I'm printing the real and imaginary parts of all complex numbers with the number of iterations it took for that number to converge (or not if the output is 255).
You need to change your while loop condition to:
while iterations < self.maxIterations and abs(z)<2:
Otherwise, the loop is running for a long time since abs(z) is less than 2.
I'm trying to use JIT to speed up some functions in my code using nopython mode. This works mostly but throws up errors in the following functions:
#jit (nopython =True)
def calc_density(pos, ncells, L):
dx = L/ncells
pos = pos/dx
#plower = pos.astype(np.int)
plower = np.int_(pos)
offset = pos - plower
opp_offset = 1- offset
density = zeros((ncells),dtype=np.float64)
for i in range(0,ncells):
ind = where((plower == i),dtype=np.float64)
density[(i+1)%ncells] += sum(offset[ind])
density[i] += sum(opp_offset[ind])
density *= float(ncells) / float(len(pos))
return (density)
#jit (nopython =True)
def periodic_interp(y, x):
ny = len(y)
if len(x) > 1:
y = array(y) # Make sure it's a NumPy array for array indexing
xl = floor(x).astype(int) # Left index
dx = x - xl
xl = ((xl % ny) + ny) % ny # Ensures between 0 and ny-1 inclusive
return y[xl]*(1. - dx) + y[(xl+1)%ny]*dx
In the first function I got the zeros part to work but this does not work for the np.where part.
The error for the first function is long but states:
[1] During: resolving callee type: Function()
For the second function the error is:
File "C:\Users\Knowhow\Anaconda3\lib\site-packages\numba\typing\npydecl.py", line 433, in _parse_nested_sequence
raise TypingError("%r not allowed in a homogenous sequence" % typ)
TypingError: array(float64, 1d, C) not allowed in a homogenous sequence
Can anyone suggest solutions to these, even if it means rewriting the function without the np.where.
Many Thanks.
Full code below:
#!/usr/bin/env python
#
# Electrostatic PIC code in a 1D cyclic domain
from numpy import arange, concatenate, zeros, linspace, floor, array, pi
from numpy import sin, cos, sqrt, random, histogram, where, sum
import numpy as np
import time
import matplotlib.pyplot as plt # Matplotlib plotting library
try:
import matplotlib.gridspec as gridspec # For plot layout grid
got_gridspec = True
except:
got_gridspec = False
# Need an FFT routine, either from SciPy or NumPy
try:
from scipy.fftpack import fft, ifft
except:
# No SciPy FFT routine. Import NumPy routine instead
from numpy.fft import fft, ifft
from numba import jit, int64
def rk4step(f, y0, dt, args=()):
""" Takes a single step using RK4 method """
k1 = f(y0, *args)
k2 = f(y0 + 0.5*dt*k1, *args)
k3 = f(y0 + 0.5*dt*k2, *args)
k4 = f(y0 + dt*k3, *args)
return y0 + (k1 + 2.*k2 + 2.*k3 + k4)*dt / 6.
##jit("f8[:](f8[:],u1,f4)")
##jit (nopython =True)
def calc_density(pos, ncells, L):
dx = L/ncells
pos = pos/dx
#plower = pos.astype(np.int)
plower = np.int_(pos)
offset = pos - plower
opp_offset = 1- offset
density = zeros((ncells),dtype=np.float64)
for i in range(0,ncells):
ind = np.where((plower == i))
density[(i+1)%ncells] += sum(offset[ind])
density[i] += sum(opp_offset[ind])
density *= float(ncells) / float(len(pos))
return (density)
##jit (nopython =True)
#jit("f8[:](f8[:], f8[:])")
def periodic_interp(y, x):
ny = len(y)
if len(x) > 1:
y = array(y) # Make sure it's a NumPy array for array indexing
#xl = floor(x).astype(int) # Left index
#d=(np.int64(p))
xl = np.int_(floor(x))
dx = x - xl
xl = ((xl % ny) + ny) % ny # Ensures between 0 and ny-1 inclusive
return y[xl]*(1. - dx) + y[(xl+1)%ny]*dx
def fft_integrate(y):
""" Integrate a periodic function using FFTs
"""
n = len(y) # Get the length of y
f = fft(y) # Take FFT
# Result is in standard layout with positive frequencies first then negative
# n even: [ f(0), f(1), ... f(n/2), f(1-n/2) ... f(-1) ]
# n odd: [ f(0), f(1), ... f((n-1)/2), f(-(n-1)/2) ... f(-1) ]
if n % 2 == 0: # If an even number of points
k = concatenate( (arange(0, n/2+1), arange(1-n/2, 0)) )
else:
k = concatenate( (arange(0, (n-1)/2+1), arange( -(n-1)/2, 0)) )
k = 2.*pi*k/n
# Modify frequencies by dividing by ik
f[1:] /= (1j * k[1:])
f[0] = 0. # Set the arbitrary zero-frequency term to zero
return ifft(f).real # Reverse Fourier Transform
def pic(f, ncells, L):
""" f contains the position and velocity of all particles
"""
nparticles = len(f)//2 # Two values for each particle
pos = f[0:nparticles] # Position of each particle
vel = f[nparticles:] # Velocity of each particle
dx = L / float(ncells) # Cell spacing
# Ensure that pos is between 0 and L
pos = ((pos % L) + L) % L
# Calculate number density, normalised so 1 when uniform
density = calc_density(pos, ncells, L)
# Subtract ion density to get total charge density
rho = density - 1.
# Calculate electric field
E = -fft_integrate(rho)*dx
# Interpolate E field at particle locations
accel = -periodic_interp(E, pos/dx)
# Put back into a single array
return concatenate( (vel, accel) )
####################################################################
##jit("f8[:],f8[:](f8[:], f8[:],f8,u1,f8[:], f8[:], f4)")
def run(pos, vel, L, ncells=None, out=[], output_times=linspace(0,20,100), cfl=0.5):
if ncells == None:
ncells = int(sqrt(len(pos))) # A sensible default
dx = L / float(ncells)
f = concatenate( (pos, vel) ) # Starting state
nparticles = len(pos)
time = 0.0
for tnext in output_times:
# Advance to tnext
stepping = True
dt = cfl * dx / max(abs(vel))
while stepping:
# Maximum distance a particle can move is one cell
if time + dt >= tnext:
# Next time will hit or exceed required output time
stepping = False
dt = tnext - time
#print "Time: ", time, dt
f = rk4step(pic, f, dt, args=(ncells, L))
time += dt
# Extract position and velocities
pos = ((f[0:nparticles] % L) + L) % L
vel = f[nparticles:]
# Send to output functions
for func in out:
func(pos, vel, ncells, L, time)
return pos, vel
####################################################################
#
# Output functions and classes
#
class Plot:
"""
Displays three plots: phase space, charge density, and velocity distribution
"""
def __init__(self, pos, vel, ncells, L):
d = calc_density(pos, ncells, L)
vhist, bins = histogram(vel, int(sqrt(len(vel))))
vbins = 0.5*(bins[1:]+bins[:-1])
# Plot initial positions
if got_gridspec:
self.fig = plt.figure()
self.gs = gridspec.GridSpec(4, 4)
ax = self.fig.add_subplot(self.gs[0:3,0:3])
self.phase_plot = ax.plot(pos, vel, '.')[0]
ax.set_title("Phase space")
ax = self.fig.add_subplot(self.gs[3,0:3])
self.density_plot = ax.plot(linspace(0, L, ncells), d)[0]
ax = self.fig.add_subplot(self.gs[0:3,3])
self.vel_plot = ax.plot(vhist, vbins)[0]
else:
self.fig = plt.figure()
self.phase_plot = plt.plot(pos, vel, '.')[0]
self.fig = plt.figure()
self.density_plot = plt.plot(linspace(0, L, ncells), d)[0]
self.fig = plt.figure()
self.vel_plot = plt.plot(vhist, vbins)[0]
plt.ion()
plt.show()
def __call__(self, pos, vel, ncells, L, t):
d = calc_density(pos, ncells, L)
vhist, bins = histogram(vel, int(sqrt(len(vel))))
vbins = 0.5*(bins[1:]+bins[:-1])
self.phase_plot.set_data(pos, vel) # Update the plot
self.density_plot.set_data(linspace(0, L, ncells), d)
self.vel_plot.set_data(vhist, vbins)
plt.draw()
plt.pause(0.05)
class Summary:
def __init__(self):
self.t = []
self.firstharmonic = []
def __call__(self, pos, vel, ncells, L, t):
# Calculate the charge density
d = calc_density(pos, ncells, L)
# Amplitude of the first harmonic
fh = 2.*abs(fft(d)[1]) / float(ncells)
#print ("Time:", t, "First:", fh)
self.t.append(t)
self.firstharmonic.append(fh)
####################################################################
#
# Functions to create the initial conditions
#
def landau(npart, L, alpha=0.2):
"""
Creates the initial conditions for Landau damping
"""
# Start with a uniform distribution of positions
pos = random.uniform(0., L, npart)
pos0 = pos.copy()
k = 2.*pi / L
for i in range(10): # Adjust distribution using Newton iterations
pos -= ( pos + alpha*sin(k*pos)/k - pos0 ) / ( 1. + alpha*cos(k*pos) )
# Normal velocity distribution
vel = random.normal(0.0, 1.0, npart)
return pos, vel
def twostream(npart, L, vbeam=2):
# Start with a uniform distribution of positions
pos = random.uniform(0., L, npart)
# Normal velocity distribution
vel = random.normal(0.0, 1.0, npart)
np2 = int(npart / 2)
vel[:np2] += vbeam # Half the particles moving one way
vel[np2:] -= vbeam # and half the other
return pos,vel
####################################################################
def main():
average_time = []
for i in range(1):
start_time = time.perf_counter()
L = 4.*pi
pos, vel = landau(10000, L)
s = Summary()
run(pos, vel, L, 10, [s], linspace(0.,30,75))
end_time = time.perf_counter()
time_difference = end_time - start_time
average_time.append(time_difference)
print ("Average time is", np.round(np.mean(average_time),2), "+/-", np.round(np.std(average_time),2))
main()
I want to resize image with bilinear interpolation. I found new intensity value but I do not know how can I use it.. The code is below which is I written..
def resizeImageBI(im,width,height):
temp = np.zeros((height,width),dtype=np.uint8)
ratio_1 = float(im.size[0] - 1 )/ float(width - 1)
ratio_0 = float(im.size[1] - 1) / float(height - 1)
xx,yy = np.mgrid[:height, :width]
xmap = np.around(xx * ratio_0)
ymap = np.around(yy * ratio_1)
for i in xrange(0, height):
for j in xrange(0,width):
temp[i][j]=im.getpixel( ( ymap[i][j], xmap[i][j]) ) * getNewIntensity(i,j,ratio_1,ratio_0)
return Image.fromarray(temp)
firstly get variable image width ratio and height ratio
lena.png 0.5 1
Orginal image is here
That is output accorting to written code
I just had to do this for a class and I haven't been graded yet, so you should check this out before using.
Basic Interpolation function
def interpolation(y0,x0, y1,x1, x):
frac = (x - x0) / (x1 - x0)
return y0*(1-frac) + y1 * frac
Step 1: Map the original coordinates to the newly resized image
def get_coords(im, W, H):
h,w = im.shape
x = np.arange(0,w+1,1) * W/w
y = np.arange(0,h+1,1) * H/h
return x,y
Step 2: Create a function to interpolate in the x-direction on all rows.
def im_interp(im, H,W):
X = np.zeros(shape=(W,H))
x, y = get_coords(im, W, H)
for i,v in enumerate(X):
y0_idx = np.argmax(y >i) - 1
for j,_ in enumerate(v):
# subtracting 1 because this is the first val
# that is greater than j, want the idx before that
x0_idx = np.argmax(x > j) - 1
x1_idx = np.argmax(j < x)
x0 = x[x0_idx]
x1 = x[x1_idx]
y0 = im[y0_idx, x0_idx - 1]
y1 = im[y0_idx, x1_idx - 1]
X[i,j] = interpolation(y0, x0, y1, x1, j)
return X
Step 3: Use function from the above step to interpolate twice. First on the image in the x-direction, then on the transpose of the newly created image (y-direction)
def im_resize(im,H,W):
X_lin = im_interp(im, H,W)
X = im_interp(X_lin.T, H,W)
return X_lin, X.T
I return both images just to look at the difference.
i'm not sure if you want to do this manually as an exercise...
if not, there is scipy.mics.imresize that can do what you want
I am trying to generate 1000 robot instances of class ROBOT
class robot:
def __init__(self):
W, H = map.size # Getting dimensions of map or image
valid_pixels = []
for y in xrange(H):
for x in xrange(W):
if ( map.getpixel((x, y)) == 255 ):
valid_pixels.append((x, y))
num_valid_pixels = len(valid_pixels)
p = valid_pixels[ random.randrange(0, num_valid_pixels) ]
self.x = p[0] + random.random();
self.y = p[1] + random.random();
self.orientation = random.uniform(0, 2 * math.pi)
self.forward_noise = 0.0
self.turn_noise = 0.0
self.sense_noise = 0.0
for i in xrange(1000):
r = robot()
It is so slow. It is taking more than 3-4 minutes. I am running Enthought in Pydev. What may be a possible problem?
But when I run the same procedure which is not under any class. It is very fast.
def initialize(map):
n = 1000
W, H = map.size # Getting dimensions of map or image
valid_pixels = []
for y in range(H):
for x in range(W):
if (map.getpixel((x, y)) == 255):
valid_pixels.append((x, y))
num_valid_pixels = len(valid_pixels)
particles = []
for i in range(n):
p = valid_pixels[random.randrange(0, num_valid_pixels)]
particles.append([p[0] + random.random(), p[1] + random.random(), random.uniform(0, 2 * math.pi)])
return particles
You're constructing the valid_pixels list 1000 times. Among other overhead, that involves 160 million map.getpixel calls, so it's pretty time-consuming. The second version of your code constructs the list once and reuses it for every random pixel selection, which is about 1000 times faster.