I've written a small program to do the following:
inspect an image
pick a row at random from the image
plot the pixel values along that row
make a list of the local minima in that row
and I'm trying to make it into a function, so that I do the same thing to, say 10 rows, so that I can plot the pixel values of all of those rows without haveing to run the program 10 times.
The code looks like this:
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
hdulist = fits.open('xbulge-w1.fits') # Open FITS file as image
w1data = hdulist[0].data
height = w1data.shape[0] # Inspect height of image
width = w1data.shape[1]
def plot_envelope(image, image_height):
index = np.random.randint(0, height/2) # Select random number in upper half
row = w1data[index] # Look at row number
local_minima = []
# Find local minimum, and add to list of minimum-valued pixels
for i in range(1, width-1):
if w1data[index][i-1] > w1data[index][i]:
if w1data[index][i+1] > w1data[index][i]:
local_minima.append(w1data[index][i])
else:
continue
return (local_minima, row, index)
plot_envelope(w1data, height)
x1 = range(width)
plt.plot(x1, row, color = 'r', linewidth = 0.5)
plt.title('Local envelope for row ' + str(index))
plt.xlabel('Position')
plt.ylabel('Pixel value')
plt.show()
It works fine if I don't use a function definition (i.e. if the declarations of index, row, and local_minima and the nested for loops are in the main part of the program). With the function definition as shown, it returns a NameError: name 'local_minima' is not defined error.
Since I'm passing those variables out of the function, shouldn't I be able to use them in the rest of the program?
Am I missing something about local and global variables?
When you call plot_envelope(w1data, height) you are telling the function to assign w1data and height to image and image_heigth respectivelly. Inside the function you should manipulate the w1data with the image dummy variable (change w1data for image inside the function) , which scope is only inside the function. Next thing is that you should get the result of the function (return) in a variable: envelope = plot_envelope(w1data, height) Then local_minima = envelope[0], row = envelope[1], index = envelope[2].
Related
As I am new to python programming. I have a problem in the for loop with index error. I have gone through the suggestions that you have given me. My problem is that in the for loop...
I didn't get any error with this code below...
for i in range(0,1):
But I have obtained an error if the limit exceeds for example (0,3)
for i in range(0,3):
The error is
IndexError: index 1 is out of bounds for axis 0 with size 1
I have tried to clear out this error and I am not sure that why this error occurs in the for loop if the limits exceed 1.
This is my code:
m=['paketone4000.dump.xlsx','paketone8000.dump.xlsx','paketone12000.dump.xlsx']
fig_name=['j4000','e8000','e12000']
fig=plt.figure(figsize=(6,6)) ##to obtain figure and dimensions of graph
for i in range(0,3):
#ax=fig.add_subplot(111,projection='3d') ## to have a broad view of figure
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot planes
p = Rectangle((0,-0.7), 4.5,1.4, color="lightgrey", alpha=0.2) #plots the background frame
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
j=pd.read_excel(m[i]) ##to read the excel file format
X=j['x'] ## to import the variable on to axes from data set
Y=j['y']
Z=j['z']
#ax.scatter(X,Y,Z,c='g', marker='o') ## to specify the color and shape of point(marker) of the frame
a=j['x']##import centre of mass from excel file format
b=j['y']
c=j['z']
q1=j['q1'], ##attaining quaternons from excel file format. (comma(,) transformed series to tuple)
q2=j['q2'],
q3=j['q3'],
q4=j['q4'],
m,n,o,p=np.array([q1,q2,q3,q4]) ## assigning quaternions to variables had converted tuple to float
Rot_Mat=QtoR(m,n,o,p)
#cuboid initialising parameters
center = [a[0], b[0], c[0]] ##centre of the body
length = 0.3 ##defining length, breadth, height
width = 0.4
height = 0.1
side = np.zeros((8,3)) ###This numpy vector will be used to store the position of the sides
#rotate the axes and update
for angle in range(0, 360):
ax.view_init(90, angle)
cuboid(center, (length, width, height)) #to execute the defined cuboid
plt.savefig(fig_name[i])
plt.clf()
print("\nq1=",m,"q2=",n,"q3=",o,"q4=",p)
print('\nRotation Matrix=',Rot_Mat)
print ("\nCenter = \n",center)
My expected result is that I want to remove the error that was obtained and I am interested in to know why that error occurred when end limit is greater than one.
You're using the name m for two different variables in your code. At the top of the file you use it to create a list of filenames, which you read in the loop. But later in the loop, you reassign it with this line:
m,n,o,p=np.array([q1,q2,q3,q4])
That causes the error when you try to read later files, as the new m value doesn't contain what the code expects (and may not be the expected size).
You should use two different variable names. This kind of issue suggest that it might be a good idea to use longer, more descriptive variable name, as you are a lot less likely to have this kind of random namespace collision with names like filenames and first_quaternion (or whatever).
I'd also suggest using range(len(m)) so that if you change the size of the list at some future time, you won't need to remember to also change the hard-coded range size.
An image for this code execution. How about you try replacing
for i in range(0, 5):
with
for i in range(len(m)):
EDIT:
Does this work?
m=['paketone4000.dump.xlsx','paketone8000.dump.xlsx','paketone12000.dump.xlsx']
fig_name=['j4000','e8000','e12000']
fig=plt.figure(figsize=(6,6)) ##to obtain figure and dimensions of graph
for index, i in enumerate(m):
#ax=fig.add_subplot(111,projection='3d') ## to have a broad view of figure
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot planes
p = Rectangle((0,-0.7), 4.5,1.4, color="lightgrey", alpha=0.2) #plots the background frame
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
j=pd.read_excel(i) ##to read the excel file format
X=j['x'] ## to import the variable on to axes from data set
Y=j['y']
Z=j['z']
#ax.scatter(X,Y,Z,c='g', marker='o') ## to specify the color and shape of point(marker) of the frame
a=j['x']##import centre of mass from excel file format
b=j['y']
c=j['z']
q1=j['q1'], ##attaining quaternons from excel file format. (comma(,) transformed series to tuple)
q2=j['q2'],
q3=j['q3'],
q4=j['q4'],
m2,n,o,p=np.array([q1,q2,q3,q4]) ## assigning quaternions to variables had converted tuple to float
Rot_Mat=QtoR(m2,n,o,p)
#cuboid initialising parameters
center = [a[0], b[0], c[0]] ##centre of the body
length = 0.3 ##defining length, breadth, height
width = 0.4
height = 0.1
side = np.zeros((8,3)) ###This numpy vector will be used to store the position of the sides
#rotate the axes and update
for angle in range(0, 360):
ax.view_init(90, angle)
cuboid(center, (length, width, height)) #to execute the defined cuboid
amount_of_files_to_rename=index
new_names = [i*1000 for i in range(4*amount_of_files_to_rename)[::4]]
for i in new_names:
plt.savefig('packetone {}.jpg'.format(i))
#plt.savefig(fig_name[b])
#plt.clf()
print("\nq1=",m2,"q2=",n,"q3=",o,"q4=",p)
print('\nRotation Matrix=',Rot_Mat)
print ("\nCenter = \n",center)
I have a piece of code which is supposed to grab all verts of an object and then through the use of "for loop" assign them a random color value inside a grayscale range.
The following code selects every vert of the mesh one by one but does not assign a color to each one of them. Instead it assigns a color to all of them at the same time filling the whole object with a uniform color.
import maya.cmds as cmds
import functools
import random
colorList =cmds.ls('colorSet*' )
sphereList = cmds.ls( 'mySphere*' )
if len( sphereList ) > 0:
cmds.delete( sphereList)
result = cmds.polySphere ( r=50, sx=random.randrange(10, 100), sy=random.randrange(10,100), name='mySphere#' )
cmds.polyColorSet ( create=True, colorSet='colorSet1')
def get_random_vertexes():
percent = 1
vertexes = []
for obj in cmds.ls(sl=1, long=1):
indexes = range(cmds.polyEvaluate(obj, vertex=1))
random.shuffle(indexes)
indexes = indexes[:int(percent*len(indexes))]
for i in range(len(indexes)):
indexes[i] = obj+'.vtx['+str(indexes[i])+']'
brightness = random.uniform(0.1,1.0)
rgb = (brightness, brightness, brightness)
cmds.polyColorPerVertex (rgb=rgb)
vertexes.extend(indexes)
cmds.select(vertexes, r=1)
get_random_vertexes()
Instead of having a noisy range of color values on the mesh it is filled with a flat color. How do I make sure each vert gets assigned a color as it's being selected while not touching other verts?
The main issue is that you don't pass anything to cmds.polyColorPerVertex so that every time you call it, it colors whatever is currently selected (in this case all verts from the sphere). If you pass a vert though that function it will set it on the single vert as expected:
import maya.cmds as cmds
import random
sphereList = cmds.ls('mySphere*')
if sphereList: # Can shorten if statement.
cmds.delete(sphereList)
new_obj, _ = cmds.polySphere (r=50, sx=random.randrange(10, 20), sy=random.randrange(10, 20), name='mySphere#')
cmds.setAttr('{}.displayColors'.format(new_obj), True) # Display vert colors.
cmds.polyColorSet(new_obj, create=True, colorSet='colorSet1')
def set_random_vertexes(percent=1): # Move percent as a parameter so it's not hard-coded.
vertexes = []
for obj in cmds.ls(sl=1, long=1):
all_verts = cmds.ls('{}.vtx[*]'.format(obj), flatten=True) # Use `cmds.ls` with `flatten` to get a list of all vertexes.
random.shuffle(all_verts)
verts = all_verts[:int(percent * len(all_verts))]
for vert in verts:
brightness = random.uniform(0.1, 1.0)
rgb = (brightness, brightness, brightness)
cmds.polyColorPerVertex(vert, rgb=rgb) # Pass vert's name to change its color.
vertexes.extend(verts)
cmds.select(vertexes, r=1)
set_random_vertexes()
I also included a few optimizations in there. You might want to consider changing the name of the function get_random_vertexes as it feels misleading by setting vertexes instead of returning a list of them.
I want my loop to only change the table cell from 0 to 5 inside the "walls".
The "walls" are user defined and could be of any shape, based on coordinates.
The plot is only for visualization.
import matplotlib.pyplot as plt
import pandas as pd
wallPointsX = [5,5,30,30,55,55,5]
wallPointsY = [5,30,30,55,55,5,5]
df = pd.DataFrame(0, index=range(60), columns=range(60))
for x in range(0, 60):
for y in range(0, 60):
df[x][y] = 5 #Should only apply inside "walls"
plt.plot(wallPointsX, wallPointsY)
plt.pcolor(df)
plt.show()
Result plot
Ok, took me some time but it was fun doing it. The idea here is to first create a continuous path out of the coordinates which define the walls. Next, create an object Path. Now you loop through each point in the DataFrame and then look if the created Path contains that (x,y) point using contains_point. I additionally had to use the condition x==55 and (5<y<=55) in the if statement so as to include the column adjacent to the
right most wall.
import matplotlib.path as mplPath
import numpy as np
wallPointsX = [5,5,30,30,55,55,5]
wallPointsY = [5,30,30,55,55,5,5]
# Create a continuous path across the wall coordinates
path = np.array([list(i) for i in zip(wallPointsX, wallPointsY)])
Path = mplPath.Path(path)
df = pd.DataFrame(0, index=range(60), columns=range(60))
for x in range(0, 60):
for y in range(0, 60):
if Path.contains_point((x,y)) or (x==55 and (5<y<=55)):
df[x-1][y-1] = 5 #Should only apply inside "walls"
plt.plot(wallPointsX, wallPointsY)
plt.pcolor(df)
Output
I have a series of methods that take an image 89x22 pixels (although the size, theoretically, is irrelevant) and fits a curve to each row of pixels to find the location of the most significant signal. At the end, I have a list of Y-values, one for each row of pixels, and a list of X-values, the location of the most significant peak for each row.
I would like to test different types of curves to see which models the data better, and in order to do so, I would like to be able to print out a new image, also 89x22 pixels, with the location of the most significant peak marked with a single red pixel for each line. A have attached an input example and a (poorly drawn) example of what I expect a good output to look like:
Any suggestions on which modules to start looking in?
class image :
def importImage (self) :
"""Open an image and sort all pixel values into a list of lists"""
from PIL import Image #imports Image from PIL library
im = Image.open("testTop.tif") #open the file
size = im.size #size object is a tuple with the pixel width and pixel height
width = size[0] #defines width object as the image width in pixels
height = size[1] #defines the height object as the image height in pixels
allPixels = list(im.getdata()) #makes a list of all pixels values
pixelList = [allPixels[width*i : width * (i+1)] for i in range(height)] #takes mega-list and makes a list of lists by row
return(pixelList) #returns list of lists
def fitCurves (self) :
"""
Iterate through a list of lists and fit a curve to each list of integers.
Append the position of the list and the location of the vertex to a growing list.
"""
from scipy.optimize import curve_fit
import numpy as np
from matplotlib import pyplot as pp
from scipy.misc import factorial
image = self.importImage()
xList = []
yList = []
position = 0
for row in image :
#Gaussian fit equations kindly provided by user mcwitt
x = np.arange(len(row))
ffunc = lambda x, a, x0, s: a*np.exp(-0.5*(x-x0)**2/s**2) # define function to fit
p, _ = curve_fit(ffunc, x, row, p0=[100,5,2]) # fit with initial guess a=100, x0=5, s=2
x0 = p[1]
yList.append(position)
position = position + 1
xList.append(x0)
print(yList)
print(xList)
newImage = image()
newImage.fitCurves()
Mabye:
import numpy as np
from matplotlib import pyplot as plt
from scipy import ndimage
from scipy import optimize
%matplotlib inline
# just a gaussian (copy paste from lmfit, another great package)
def my_gaussian(p,x):
amp = p[0]
cen = p[1]
wid = p[2]
return amp * np.exp(-(x-cen)**2 /wid)
# I do like to write a cost function separately. For the leastsquare algorithm it should return a vector.
def my_cost(p,data):
return data - my_gaussian(p,data)
# i load the image and generate the x values
image = ndimage.imread('2d_gaussian.png',flatten=True)
x = np.arange(image.shape[1])
popt = []
# enumerate is a convenient way to loop over an iterable and keep track of the index.
y = []
for index,data in enumerate(image):
''' this is the trick to make the algorithm robust.
I do plug the index of the maximum value of the current row as
initial guess for the center. Maybe it would be enough to do
just that and the fit is unnecessary. Haven`t checked that.
'''
max_index = np.argmax(data)
# initial guess.
x0 = [1.,max_index,10]
# call to the solver
p,_ = optimize.leastsq(my_cost, x0, args = data)
popt.append(p)
y.append(index)
'''
I do transpose the data.
As a consequence the values are stored row, not columnwise.
It is often easier to store the reusults inside a loop and
convert the data later into a numpy array.
'''
gaussian_hat = np.array(popt).T
# without the transpose, it would be center = gaussian_hat[:,1]
center = gaussian_hat[1]
y = np.array(y)
''' i do like to use an axis handle for the plot.
Not necessary, but gives me the opportunity to add new axis if necessary.
'''
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.imshow(image)
# since it is just a plot, I can plot the x, y coordinates
ax.plot(center,y,'k-')
# fitt of a 3th order polynomial
poly = np.polyfit(y,center,3)
# evaluation at points y
x_hat = np.polyval(poly,y)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.imshow(image)
ax.plot(x_hat,y,'k-')
plt.savefig('2d_gaussian_fit.png')
So I have an array (it's large - 2048x2048), and I would like to do some element wise operations dependent on where they are. I'm very confused how to do this (I was told not to use for loops, and when I tried that my IDE froze and it was going really slow).
Onto the question:
h = aperatureimage
h[:,:] = 0
indices = np.where(aperatureimage>1)
for True in h:
h[index] = np.exp(1j*k*z)*np.exp(1j*k*(x**2+y**2)/(2*z))/(1j*wave*z)
So I have an index, which is (I'm assuming here) essentially a 'cropped' version of my larger aperatureimage array. *Note: Aperature image is a grayscale image converted to an array, it has a shape or text on it, and I would like to find all the 'white' regions of the aperature and perform my operation.
How can I access the individual x/y values of index which will allow me to perform my exponential operation? When I try index[:,None], leads to the program spitting out 'ValueError: broadcast dimensions too large'. I also get array is not broadcastable to correct shape. Any help would be appreciated!
One more clarification: x and y are the only values I would like to change (essentially the points in my array where there is white, z, k, and whatever else are defined previously).
EDIT:
I'm not sure the code I posted above is correct, it returns two empty arrays. When I do this though
index = (aperatureimage==1)
print len(index)
Actually, nothing I've done so far works correctly. I have a 2048x2048 image with a 128x128 white square in the middle of it. I would like to convert this image to an array, look through all the values and determine the index values (x,y) where the array is not black (I only have white/black, bilevel image didn't work for me). I would then like to take all the values (x,y) where the array is not 0, and multiply them by the h[index] value listed above.
I can post more information if necessary. If you can't tell, I'm stuck.
EDIT2: Here's some code that might help - I think I have the problem above solved (I can now access members of the array and perform operations on them). But - for some reason the Fx values in my for loop never increase, it loops Fy forever....
import sys, os
from scipy.signal import *
import numpy as np
import Image, ImageDraw, ImageFont, ImageOps, ImageEnhance, ImageColor
def createImage(aperature, type):
imsize = aperature*8
middle = imsize/2
im = Image.new("L", (imsize,imsize))
draw = ImageDraw.Draw(im)
box = ((middle-aperature/2, middle-aperature/2), (middle+aperature/2, middle+aperature/2))
import sys, os
from scipy.signal import *
import numpy as np
import Image, ImageDraw, ImageFont, ImageOps, ImageEnhance, ImageColor
def createImage(aperature, type):
imsize = aperature*8 #Add 0 padding to make it nice
middle = imsize/2 # The middle (physical 0) of our image will be the imagesize/2
im = Image.new("L", (imsize,imsize)) #Make a grayscale image with imsize*imsize pixels
draw = ImageDraw.Draw(im) #Create a new draw method
box = ((middle-aperature/2, middle-aperature/2), (middle+aperature/2, middle+aperature/2)) #Bounding box for aperature
if type == 'Rectangle':
draw.rectangle(box, fill = 'white') #Draw rectangle in the box and color it white
del draw
return im, middle
def Diffraction(aperaturediameter = 1, type = 'Rectangle', z = 2000000, wave = .001):
# Constants
deltaF = 1/8 # Image will be 8mm wide
z = 1/3.
wave = 0.001
k = 2*pi/wave
# Now let's get to work
aperature = aperaturediameter * 128 # Aperaturediameter (in mm) to some pixels
im, middle = createImage(aperature, type) #Create an image depending on type of aperature
aperaturearray = np.array(im) # Turn image into numpy array
# Fourier Transform of Aperature
Ta = np.fft.fftshift(np.fft.fft2(aperaturearray))/(len(aperaturearray))
# Transforming and calculating of Transfer Function Method
H = aperaturearray.copy() # Copy image so H (transfer function) has the same dimensions as aperaturearray
H[:,:] = 0 # Set H to 0
U = aperaturearray.copy()
U[:,:] = 0
index = np.nonzero(aperaturearray) # Find nonzero elements of aperaturearray
H[index[0],index[1]] = np.exp(1j*k*z)*np.exp(-1j*k*wave*z*((index[0]-middle)**2+(index[1]-middle)**2)) # Free space transfer for ap array
Utfm = abs(np.fft.fftshift(np.fft.ifft2(Ta*H))) # Compute intensity at distance z
# Fourier Integral Method
apindex = np.nonzero(aperaturearray)
U[index[0],index[1]] = aperaturearray[index[0],index[1]] * np.exp(1j*k*((index[0]-middle)**2+(index[1]-middle)**2)/(2*z))
Ufim = abs(np.fft.fftshift(np.fft.fft2(U))/len(U))
# Save image
fim = Image.fromarray(np.uint8(Ufim))
fim.save("PATH\Fim.jpg")
ftfm = Image.fromarray(np.uint8(Utfm))
ftfm.save("PATH\FTFM.jpg")
print "that may have worked..."
return
if __name__ == '__main__':
Diffraction()
You'll need numpy, scipy, and PIL to work with this code.
When I run this, it goes through the code, but there is no data in them (everything is black). Now I have a real problem here as I don't entirely understand the math I'm doing (this is for HW), and I don't have a firm grasp on Python.
U[index[0],index[1]] = aperaturearray[index[0],index[1]] * np.exp(1j*k*((index[0]-middle)**2+(index[1]-middle)**2)/(2*z))
Should that line work for performing elementwise calculations on my array?
Could you perhaps post a minimal, yet complete, example? One that we can copy/paste and run ourselves?
In the meantime, in the first two lines of your current example:
h = aperatureimage
h[:,:] = 0
you set both 'aperatureimage' and 'h' to 0. That's probably not what you intended. You might want to consider:
h = aperatureimage.copy()
This generates a copy of aperatureimage while your code simply points h to the same array as aperatureimage. So changing one changes the other.
Be aware, copying very large arrays might cost you more memory then you would prefer.
What I think you are trying to do is this:
import numpy as np
N = 2048
M = 64
a = np.zeros((N, N))
a[N/2-M:N/2+M,N/2-M:N/2+M]=1
x,y = np.meshgrid(np.linspace(0, 1, N), np.linspace(0, 1, N))
b = a.copy()
indices = np.where(a>0)
b[indices] = np.exp(x[indices]**2+y[indices]**2)
Or something similar. This, in any case, sets some values in 'b' based on the x/y coordinates where 'a' is bigger than 0. Try visualizing it with imshow. Good luck!
Concerning the edit
You should normalize your output so it fits in the 8 bit integer. Currently, one of your arrays has a maximum value much larger than 255 and one has a maximum much smaller. Try this instead:
fim = Image.fromarray(np.uint8(255*Ufim/np.amax(Ufim)))
fim.save("PATH\Fim.jpg")
ftfm = Image.fromarray(np.uint8(255*Utfm/np.amax(Utfm)))
ftfm.save("PATH\FTFM.jpg")
Also consider np.zeros_like() instead of copying and clearing H and U.
Finally, I personally very much like working with ipython when developing something like this. If you put the code in your Diffraction function in the top level of your script (in place of 'if __ name __ &c.'), then you can access the variables directly from ipython. A quick command like np.amax(Utfm) would show you that there are indeed values!=0. imshow() is always nice to look at matrices.