├── .gitignore ├── INSTALL ├── LICENSE ├── README.md ├── bin └── genfire ├── data └── vesicle.mrc ├── documentation ├── .DS_Store ├── GUI_parameters.html ├── html_helper.py ├── images │ ├── CalculateProjection_dialog_empty.png │ ├── CalculateProjection_dialog_ready.png │ ├── GENFIRE.png │ ├── ProjectionCalculator_blank.png │ ├── ProjectionCalculator_modelLoaded.png │ ├── gui.png │ ├── gui_finished.png │ ├── gui_ready.png │ ├── summarize_results.png │ └── volume_slicer.png ├── index.html ├── installation.html ├── main.css ├── make_html.txt ├── src_html │ ├── CalculateProjectionSeries_Dialog.html │ ├── GENFIRE_MainWindow.html │ ├── GENFIRE_qrc.html │ ├── GENFIRE_qrc_py3.html │ ├── GENFIRE_rc.html │ ├── ProjectionCalculator.html │ ├── ProjectionCalculator_MainWindow.html │ ├── VolumeSlicer.html │ ├── VolumeSlicer_MainWindow.html │ ├── __init__.html │ ├── fileio.html │ ├── html_helper.html │ ├── launch.html │ ├── main.css │ ├── main.html │ ├── projections.html │ ├── reconstruct.html │ ├── setup.html │ └── utility.html └── tutorial.html ├── genfire ├── __init__.py ├── fileio.py ├── gui │ ├── CalculateProjectionSeries_Dialog.py │ ├── GENFIRE.png │ ├── GENFIRE.pro │ ├── GENFIRE.pro.user │ ├── GENFIRE.pro.user.bd486de │ ├── GENFIRE.qrc │ ├── GENFIRE_MainWindow.cpp │ ├── GENFIRE_MainWindow.h │ ├── GENFIRE_MainWindow.py │ ├── GENFIRE_MainWindow.ui │ ├── GENFIRE_qrc.py │ ├── GENFIRE_qrc_py3.py │ ├── GF.icns │ ├── GF.png │ ├── ProjectionCalculator.py │ ├── ProjectionCalculator_MainWindow.py │ ├── ProjectionCalculator_MainWindow.ui │ ├── VolumeSlicer.py │ ├── VolumeSlicer_MainWindow.py │ ├── VolumeSlicer_MainWindow.ui │ ├── __init__.py │ ├── calculateprojectionseries_dialog.ui │ ├── launch.py │ └── utility.py ├── main.py ├── reconstruct.py └── utility.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | GENFIRE.egg-info/ 2 | .idea/ 3 | .DS_Store 4 | build/ 5 | dist/ 6 | UNKNOWN.egg-info/ 7 | PhaseRetrieval/ 8 | dist/ 9 | build/ 10 | *.tif 11 | *.tiff 12 | *.xml 13 | *.pyc 14 | *rec*.mrc 15 | *rec*.txt 16 | results* 17 | test* 18 | projections* 19 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | First install dependencies with pip: 2 | 3 | $ pip install -r requirements.txt 4 | 5 | You will also need to download sip and PyQt. More detail is given 6 | in the GENFIRE documentation. 7 | 8 | https://www.riverbankcomputing.com/software/sip/intro 9 | http://pyqt.sourceforge.net/Docs/PyQt4/installation.html 10 | 11 | Finally, install GENFIRE with 12 | 13 | $ python setup.py install 14 | 15 | You can verify that the install worked with 16 | 17 | $ python -c "import GENFIRE" 18 | 19 | If no errors occur, the installation was successful. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GENFIRE 2 | GENeralized Fourier Iterative REconstruction (GENFIRE) is a python package for 3D reconstruction from arbitrarily oriented projection images 3 | ## Documentation 4 | The full documentation for installing/using GENFIRE is the website in ./documentation/ and can be viewed by opening ./documentation/index.html in a web browser 5 | -------------------------------------------------------------------------------- /bin/genfire: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import genfire as gf 3 | gf.gui.launch.main() 4 | -------------------------------------------------------------------------------- /data/vesicle.mrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/data/vesicle.mrc -------------------------------------------------------------------------------- /documentation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/.DS_Store -------------------------------------------------------------------------------- /documentation/GUI_parameters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GENFIRE GUI Parameters 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 40 | 41 | 42 | 43 |

GUI Parameter Details

44 |
GENFIRE Main Window
45 |

46 | "Select Projection File" - Choose filename containing projection images. Alternatively you enter a file by editing 47 | the text, but it must be a valid file type.
48 | "Use default support" - Automatically generate a cubic support defined by the oversampling ratio. For example 49 | if the projections are size 128x128 and the oversampling ratio is set to 3, the default support will be 50 | 384x384x384 with a central 128x128x128 region of 1's and the remaining region set to 0. Uncheck to enter a filename manually.
51 | "Select Support File" - Choose filename containing the 3D support. Alternatively you enter a file by editing 52 | the text, but it must be a valid file type. The array width should match that of the inputted projections.
53 | "Select Angle File" - Choose filename with the Euler angles. 54 | "Provide initial object" - Check to enable selection of an intial model. 55 | "Select Initial Object File" - Choose filename containing the initial model. 56 | "Results Filename" - Filename for the output volume. Must be a valid filetype. Error curves 57 | are saved as .txt files with the same base filename as the results. 58 | "Resolution Extension/Suppression" - Choose the style of constraint enforcement.

59 | 66 |

67 | "Number of Iterations" - Number of GENFIRE iterations to use
68 | "Oversampling Ratio" - Final oversampling ratio to use when gridding the projections. Larger oversampling ratios 69 | will produce more accurate griddings at the cost of larger array size. Ideally use at least 3.
70 | "Interpolation Cutoff Distance (pixels)" - Size of the interpolation kernel used for gridding. Small radii 71 | will result in an assembled grid with fewer values, but more accurate ones. Conversely, larger values for this 72 | parameter will be more accepting of datapoints, but at the cost of accuracy. The default 0.7 was found to be 73 | ideal based on simulations.
74 | "Summarize Results" - Display a summary of reconstruction results. Choose a volume file, and projections and central 75 | slices along the three principal directions will appear. Error curves will be plotted if the corresponding files exist. 76 | "Launch Reconstruction" - Begin the reconstruction, if the parameters are valid.
77 |

78 |
Projection Calculator
79 |

80 | "Model" - Filename of volume from which to calculate projections.
81 | "Clear Model" - Clear display and model from memory.
82 | "Calculate Projection Series from Model" - Use the current model to simulate a series of projections.
83 | "Phi" - set Phi Euler angle interactively.
84 | "Theta" - set Theta Euler angle interactively.
85 | "Psi" - set Psi Euler angle interactively.
86 |

87 |
Volume Slicer
88 |

89 | "X" - Set X value for the YZ plane.
90 | "Y" - Set Y value for the XZ plane.
91 | "Z" - Set Z value for the XY plane.
92 | "Lock Colormap" - If checked, locks the colormap for each image based on the current ones. If you want to lock 93 | a different colormap, uncheck the box, move the slicer, and recheck the box to lock the new setting. 94 |

95 | 96 |
97 | 98 | -------------------------------------------------------------------------------- /documentation/html_helper.py: -------------------------------------------------------------------------------- 1 | """ 2 | bla 3 | """ 4 | def generate_html(filename=None): 5 | #convert source code files into formatted html for documentation 6 | import sys 7 | import os 8 | print(filename) 9 | if not os.path.isfile(filename): 10 | raise NameError("File Not Found") 11 | 12 | # if filename is None and len(sys.argv)>1: 13 | # filename=sys.argv[1] 14 | html_filename = os.path.abspath(os.path.splitext(filename)[0]) + '.html' 15 | header_str = """ 16 | 17 | 18 | 19 | """ + os.path.splitext(filename)[0] + """ 20 | 21 | \ 22 | 23 | 24 | 25 | \n""" 26 | 27 | closing_str = """ 28 | """ 29 | print("hs = {}".format(header_str)) 30 | 31 | with open(filename,'r') as fid_source: 32 | with open(html_filename,'w') as fid: 33 | print ("html_filename = " , html_filename) 34 | fid.write(header_str) 35 | fid.write("") 36 | in_comment_flag = 0 37 | for line in fid_source: 38 | if line.lstrip().startswith("#"): # then this line is a single line comment and we don't format it 39 | fid.write(line.replace('\n',"
")) 40 | elif line.lstrip().startswith("\"\"\""): # ignore formatting on multi-line comments 41 | fid.write(line.replace('\n',"
")) 42 | in_comment_flag = (in_comment_flag + 1) % 2 43 | elif in_comment_flag: 44 | fid.write(line.replace('\n',"
")) 45 | else: 46 | inline_comment_start = line.find("#") 47 | if inline_comment_start == -1: # no inline comment 48 | fid.write(code_formatter(line)) 49 | else: 50 | fid.write(code_formatter(line[:inline_comment_start].replace('\n',"
"))) 51 | fid.write(line[inline_comment_start:].replace('\n',"
")) 52 | fid.write("
") 53 | fid.write(closing_str) 54 | 55 | def code_formatter(string): 56 | # A simple custom HTML code formatter that colors some keywords and tries to avoid instances of them within comments 57 | color_string = "\"orange\"" 58 | keywords = ["from", "def","class", "self", "__main__", "for", "if",\ 59 | "while","import","else","elif", "True","False", "del", \ 60 | "with", "plt", "QtCore", "QtGui", "Qt", "ui"] 61 | short_keywords = keywords[:] 62 | new_keywords = [] 63 | for i, v in enumerate(keywords): 64 | keywords[i] = v + " " 65 | new_keywords.append(v + ".") 66 | new_keywords.append(v + "\n") 67 | keywords += new_keywords 68 | format_string = ("", "") 69 | replacers={} 70 | 71 | for kw in keywords: 72 | replacers[kw] = format_string 73 | 74 | GENFIRE_format_string = ("", "") 75 | replacers['GENFIRE'] = GENFIRE_format_string 76 | replacers['genfire'] = GENFIRE_format_string 77 | 78 | 79 | 80 | # replacers={"from":("", "")} 81 | 82 | 83 | 84 | string = string.replace('\t', "    ") 85 | if replacers is not None: 86 | for key, value in replacers.iteritems(): 87 | # print (key, value) 88 | string = string.replace(key,value[0] + key + value[1]) 89 | 90 | # for key in short_keywords: 91 | # if string.endswith(key): 92 | # string.replace(key, ("" + key+ "") ) 93 | string = string.replace('\n',"
") 94 | return string 95 | 96 | if __name__=="__main__": 97 | import sys 98 | if len(sys.argv) > 1: 99 | for j in range(1,len(sys.argv)): 100 | generate_html(sys.argv[j]) 101 | else: 102 | generate_html("html_helper.py") 103 | -------------------------------------------------------------------------------- /documentation/images/CalculateProjection_dialog_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/CalculateProjection_dialog_empty.png -------------------------------------------------------------------------------- /documentation/images/CalculateProjection_dialog_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/CalculateProjection_dialog_ready.png -------------------------------------------------------------------------------- /documentation/images/GENFIRE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/GENFIRE.png -------------------------------------------------------------------------------- /documentation/images/ProjectionCalculator_blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/ProjectionCalculator_blank.png -------------------------------------------------------------------------------- /documentation/images/ProjectionCalculator_modelLoaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/ProjectionCalculator_modelLoaded.png -------------------------------------------------------------------------------- /documentation/images/gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/gui.png -------------------------------------------------------------------------------- /documentation/images/gui_finished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/gui_finished.png -------------------------------------------------------------------------------- /documentation/images/gui_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/gui_ready.png -------------------------------------------------------------------------------- /documentation/images/summarize_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/summarize_results.png -------------------------------------------------------------------------------- /documentation/images/volume_slicer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/images/volume_slicer.png -------------------------------------------------------------------------------- /documentation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GENFIRE Tutorial 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |



Welcome to

19 | 23 | 24 |
25 |
26 |
Introduction
27 |

28 | GENFIRE, for GENeralized Fourier Iterative REconstruction, is an open-sourced, GUI-enabled 29 | python package for 3D reconstruction from arbitrarily oriented projection images. GENFIRE 30 | was developed at the University of California, Los Angeles and has found 31 | successful applications in a number of imaging fields including Atomic Electron Tomography (AET), 32 | electron cryo-tomography, tomographic Scanning Transmission X-ray Microscopy (STXM), and 33 | phase-contrast X-ray ptychographic tomography.

34 | GENFIRE iterates between real and reciprocal space using the Fast Fourier Transform (FFT), 35 | enforcing constraints in both. This technique of alternating projections onto convex sets allows 36 | GENFIRE to recover unmeasured datapoints, producing reconstructions with superior contrast 37 | and mitigated missing-wedge artifacts when compared with traditional tomographic techniques such as 38 | filtered backprojection. This type of reconstruction algorithm was originally demonstrated 39 | in the form of Equally Sloped Tomography (EST). GENFIRE builds upon EST by introducing a 3D 40 | gridding routine, allowing it to tolerate arbitrary Euler rotations of the input projection images. 41 | In addition, GENFIRE introduces a novel technique for enforcing Fourier constraints deemed 42 | resolution extension/suppression and implements a modified version of R-free from X-ray crystallography 43 | for the purposes of prevention of overfitting data.

44 | GENFIRE is written in python using primarily NumPy and SciPy. It runs on python 3 and the GUI is programmed using PyQt5. 45 | The user interface was designed with Qt Creator. Embedded plots were made with matplotlib. 46 | 47 | 48 |

49 |
Getting started
50 |

51 | GENFIRE can be downloaded for free here. There are precompiled binaries for Mac OS X, Windows, and Linux, 52 | and the code is also available as a python package. Installation instructions are 53 | here Once you have installed GENFIRE, check out the 54 | tutorial. 55 |

56 |
About
57 |
Coordinate Conventions
58 | 59 |

60 | The coordinate and Euler angle conventions used in GENFIRE are the standard defined by 61 | Heymann et. al (2005).
For 3D 62 | arrays the fastest changing index represents X, the second-fastest represents Y, and the slowest 63 | Z. GENFIRE is built on top of NumPy and uses row-major array storage (sometimes called "C-style". 64 | As such an array is indexed as [x, y, z].
65 | Euler rotations are composed of angle triplets in the form (phi, theta, psi) where: 66 |

71 | *Note* in the current implementation, array sizes must be even. 72 |

73 |
File Formats
74 |

75 | GENFIRE natively works with .mrc, 76 | .mat, and 77 | .npy files for volume data. 78 | Euler angle triplets and error curves are stored as plain .txt files. File formats can 79 | be mix-and-matched using the GUI without trouble, or users can convert filetypes from 80 | the command line using GENFIRE's fileio module. For example the following code reads in 81 | an .mrc file and saves it in .mat format. 82 |

83 |
84 | $ from GENFIRE.fileio import readVolume, writeVolume
85 | $ volume = readVolume('foo.mrc')
86 | $ writeVolume('bar.mat', volume)
87 |
88 |
89 |

90 | 112 | 113 |
Author Information
114 |

115 | Author: Alan (AJ) Pryor, Jr.
116 | Jianwei (John) Miao Coherent Imaging Group
117 | University of California, Los Angeles
118 | Copyright 2015-2016. All rights reserved. 119 |

120 | 121 |
122 | 123 | 124 | -------------------------------------------------------------------------------- /documentation/installation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GENFIRE Tutorial 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 41 | 42 | 43 | 44 | 45 |

Installation

46 |
Get the Source Code
47 | 48 |

49 | To install GENFIRE as a python package, first 50 | download the source code. Then follow the procedure for 51 | your operating system. 52 |

53 | 54 | 55 |
Mac OS X
56 | 57 |

58 | Python is preinstalled on Mac OS X, but it is generally a bad idea to alter the system 59 | python in /usr/bin as some programs depend on it. I would highly recommend using the 60 | package manager homebrew to create a python environment for you. The following 61 | commands will install homebrew and python3 62 |

63 |

64 |
65 |
66 | $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
67 | $ brew install python3 68 |
69 |
70 |

71 |

72 | Once that's done, navigate to the top source code directory. That's the same 73 | folder as requirements.txt and setup.py

74 |
75 |
76 | $ cd /path/to/GENFIRE 77 |
78 |
79 |

80 | Install (most of the) dependencies using pip3, you may need to prepend the command with sudo depending on your system

81 |
82 |
83 | $ pip install --upgrade pip
84 | $ pip3 install -r requirements.txt 85 |
86 |
87 | 88 |

89 |

90 | You will also need sip and PyQt5: 91 |

92 |
93 |
94 | $ brew install sip
95 | $ brew install pyqt 96 |
97 |
98 |

99 | You should now have all the dependencies necessary to run GENFIRE. To install it, make 100 | sure you are in the directory with setup.py and enter the follow. Again, you may need sudo 101 |

102 |
103 |
104 | $ python3 setup.py install 105 |
106 |
107 |

108 | If everything worked, you can now launch the gui from the command line with 109 |

110 |
111 |
112 | $ genfire 113 |
114 |
115 |

116 | You can also use the code as any other python package. Here's an example of launching the gui from within python 117 |

118 |
119 |
120 | $ python3
121 | $ import GENFIRE
122 | $ GENFIRE.gui.launch.main() 123 |
124 |
125 |

126 | 127 |

(Optional) Turbo-charge GENFIRE with FFTW
128 |

GENFIRE can make use of pyFFTW, which wraps the FFTW library. I have tested a number of 129 | FFT routines including those in NumPy, SciPy, and pyFFTW, and found this to be the fastest one by a factor of 2-3. 130 |

131 | 132 |

133 | The following are details for installing FFTW from source, but recently pip has begun to support the package, so you should first try the easy way with 134 | "pip install pyfftw" 135 |

136 |

137 | In order for GENFIRE to use pyFFTW you must install 138 | the FFTW libraries. Download the source code, decompress it, and navigate into the unpacked directory 139 | from your terminal. PyFFTW needs FFTW to be compiled for all precision types, so you have to compile it three times. 140 | Use the following commands 141 |

142 |
143 | $ ./configure --enable-threads --enable-shared
144 | $ make
145 | $ sudo make install 146 |
147 |
148 |

as well as

149 |
150 |
151 | $ ./configure --enable threads --enable-shared --enable-float
152 | $ make
153 | $ sudo make install 154 |
155 |
156 |

and finally

157 |
158 |
159 | $ ./configure --enable threads --enable-shared --enable-long-double
160 | $ make
161 | $ sudo make install 162 |
163 |
164 |

Now, install pyFFTW with pip and and test that it worked

165 | 166 |
167 |
168 | $ pip install pyfftw
169 | $ python -c "import pyfftw" 170 |
171 |
172 |

If you don't receive an error, then it was successful. If you get an error along the lines of 173 | "ImportError: libfftw3l.so cannot open shared object file" then you need to set your DYLD_LIBRARY_PATH 174 | environmental variable so that pyFFTW can find the libraries

175 |
176 |
177 | $ export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
178 |
179 |
180 |

If the fftw .so files are somewhere other than /usr/local/lib, then you should replace that part appropriately. 181 | To make this change permanent add the above line to the end of your ~/.bash_profile

182 | 183 |

Linux (Ubuntu 14.04)
184 |

185 | Navigate to the source code directory. That's the same folder as requirements.txt and setup.py

186 |
187 |
188 | $ cd /path/to/GENFIRE 189 |
190 |
191 |

192 | Install (most of the) dependencies using pip

193 |
194 |
195 | $ pip install --upgrade pip
196 | $ sudo pip install -r requirements.txt 197 |
198 |
199 |

200 | You will also need sip and PyQt4, this command should install both.

201 |
202 |
203 | $ sudo apt-get install python-qt4
204 |
205 |
206 | 207 |

208 |

209 | You should now have all the dependencies necessary to run GENFIRE. To install it, make 210 | sure you are in the directory with setup.py and enter 211 |

212 |
213 |
214 | $ sudo python setup.py install 215 |
216 |
217 |

218 | If everything worked, you can now launch the gui from the command line with 219 |

220 |
221 |
222 | $ genfire 223 |
224 |
225 |

226 | You can also use the code as any other python package. Here's an example of launching the gui from within python 227 |

228 |
229 |
230 | $ python
231 | $ import GENFIRE
232 | $ GENFIRE.gui.launch.main() 233 |
234 |
235 |

236 |

(Optional) Turbo-charge GENFIRE with FFTW
237 |

GENFIRE can make use of pyFFTW, which wraps the FFTW library. I have tested a number of 238 | FFT routines including those in NumPy, SciPy, and pyFFTW, and found this to be the fastest one by a factor of 2-3. 239 |

240 |

241 | The following are details for installing FFTW from source, but recently pip has begun to support the package, 242 | so you should first try the easy way with "pip install pyfftw" 243 | 244 |

245 |

246 | In order for GENFIRE to use pyFFTW you must install 247 | the FFTW libraries. Download the source code, decompress it, and navigate into the unpacked directory 248 | from your terminal. PyFFTW needs FFTW to be compiled for all precision types, so you have to compile it three times. 249 | Use the following commands 250 |

251 |
252 | $ ./configure --enable-threads --enable-shared
253 | $ make
254 | $ sudo make install 255 |
256 |
257 |

as well as

258 |
259 |
260 | $ ./configure --enable threads --enable-shared --enable-float
261 | $ make
262 | $ sudo make install 263 |
264 |
265 |

and finally

266 |
267 |
268 | $ ./configure --enable threads --enable-shared --enable-long-double
269 | $ make
270 | $ sudo make install 271 |
272 |
273 |

Now, install pyFFTW with pip and and test that it worked

274 | 275 |
276 |
277 | $ pip install pyfftw
278 | $ python -c "import pyfftw" 279 |
280 |
281 |

If you don't receive an error, then it was successful. If you get an error along the lines of 282 | "ImportError: libfftw3l.so cannot open shared object file" then you need to set your LD_LIBRARY_PATH 283 | environmental variable so that pyFFTW can find the libraries

284 |
285 |
286 | $ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
287 |
288 |
289 |

If the fftw .so files are somewhere other than /usr/local/lib, then you should replace that part appropriately. 290 | To make this change permanent add the above line to the end of your ~/.bashrc

291 | 292 |

Windows 10
293 |

294 | For python on Windows 10 I would recommend using 295 | Anaconda from Continuum Analytics. It's a distribution of python that contains 296 | most of the packages used by GENFIRE all wrapped into a simple-to-use installer. Note you must use python 3.
297 | Once you have python setup, open up a cmd prompt and navigate to the source directory. 298 | That's the same folder as requirements.txt and setup.py 299 |

300 | 301 |

302 | Now install GENFIRE with

303 |
304 |
305 | $ C:\path\to\Anaconda\python setup.py install
306 |
307 |
308 |

309 | If everything worked you can now launch the gui. 310 |

311 |
312 |
313 | $ C:\path\to\Anaconda\python GENFIRE\gui\launch.py 314 |
315 |
316 | 317 | You can also use the code as any other python package. Here's an example of launching the gui from within python 318 |

319 |
320 |
321 | $ python
322 | $ import GENFIRE
323 | $ GENFIRE.gui.launch.main() 324 |
325 |
326 |

327 | 328 |

(Optional) Turbo-charge GENFIRE with FFTW
329 |

GENFIRE can make use of pyFFTW, which wraps the FFTW library. I have tested a number of 330 | FFT routines including those in NumPy, SciPy, and pyFFTW, and found this to be the fastest one by a factor of 2-3. 331 | On Windows, pyFFTW can be installed simply with 332 |

333 |
334 | $ C:\path\to\Anaconda\Scripts\pip install pyfftw 335 |
336 |
337 | 338 |

339 |

Installation Troubleshooting
340 |

341 | If you have trouble installing PyQt4 or sip, consult their 342 | documentation
343 | If you have some problem with the "pip install -r requirements.txt" step, you can view 344 | the requirements.txt file to see the packages that are necessary, and try to install 345 | them one-by-one. 346 |

347 |
348 | 349 | 350 | 356 | -------------------------------------------------------------------------------- /documentation/main.css: -------------------------------------------------------------------------------- 1 | #bounding_box { 2 | width:85%; 3 | padding = 14px 40px; 4 | text-align:justify; 5 | overflow-x: scroll; 6 | } 7 | h1 { 8 | margin: 10px; 9 | padding: 14px 0px; 10 | font-size: 36px; 11 | font-weight: bold; 12 | background-color: black; 13 | color: #ffffff; 14 | text-align: center 15 | } 16 | .h1_left { 17 | margin: 10px; 18 | padding: 14px 0px; 19 | font-size: 36px; 20 | font-weight: bold; 21 | color: #ffffff; 22 | background-color: black; 23 | 24 | text-align: left; 25 | } 26 | 27 | 28 | body { 29 | margin: 0; 30 | padding: 0; 31 | line-height: 1.5em; 32 | font-family: Arial, Helvetica, sans-serif; 33 | font-size: 16px; 34 | color: #AAAAAA; 35 | background: #080808; 36 | background: black; 37 | overflow-x: scroll; 38 | 39 | } 40 | 41 | a:link, a:visited { 42 | color: #ff6600; 43 | color:orange; 44 | text-decoration: none; 45 | font-weight: normal; 46 | } 47 | 48 | a:active, a:hover{ 49 | color: #FFCC00; 50 | color:orange; 51 | text-decoration: underline; 52 | } 53 | 54 | p { 55 | margin: 10px; 56 | margin-right:155px; 57 | padding: 0px; 58 | text-align:justify; 59 | } 60 | 61 | ul{ 62 | margin: 10px; 63 | margin-right:155px; 64 | padding: 15px; 65 | text-align:justify; 66 | } 67 | 68 | .code_box{ 69 | width: 85%; 70 | text-align: justify; 71 | } 72 | .code { 73 | height:150%; 74 | /* margin-left:500px; */ 75 | margin-top:100px; 76 | background:#666666; 77 | color:orange; 78 | margin: 25px 25px 25px 25px; 79 | /* margin-right:155px; */ 80 | /* margin:0 auto; */ 81 | padding: 15; 82 | text-align:justify; 83 | width:1000px; 84 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 85 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 86 | } 87 | 88 | 89 | img { 90 | margin: 0px; 91 | padding: 30px; 92 | border: none; 93 | } 94 | 95 | h2 { 96 | position: relative; 97 | height: 25px; 98 | margin: 0px; 99 | padding: 10px 0 0 0; 100 | font-size: 20px; 101 | font-weight: bold; 102 | text-align: left; 103 | color: #000000; 104 | color:white 105 | } 106 | 107 | 108 | h3 { 109 | margin: 0 0 5px 0; 110 | padding: 2px 0 3px 0; 111 | font-size: 14px; 112 | font-weight: normal; 113 | color: #d7e13d; 114 | color: orange; 115 | border-bottom: 1px dotted #d7e13d; 116 | } 117 | 118 | .h2_left { 119 | margin-left:10px; 120 | font-size: 24px; 121 | font-weight: bold; 122 | background-color: black; 123 | color: #ffffff; 124 | text-align: left; 125 | text-decoration:underline; 126 | /* float: left */ 127 | } 128 | .h2_center { 129 | margin-left:10px; 130 | font-size: 42px; 131 | padding-top: 10px; 132 | padding-bottom: 10px; 133 | font-weight: bold; 134 | background-color: black; 135 | color: #ffffff; 136 | text-align: center; 137 | text-decoration:underline; 138 | /* float: left */ 139 | } 140 | .h3_left { 141 | margin-left:10px; 142 | font-size: 20px; 143 | font-weight: bold; 144 | background-color: black; 145 | color: #ffffff; 146 | text-align: left; 147 | text-decoration:/* underline */; 148 | /* float: left */ 149 | } 150 | .h5_left { 151 | margin-left:10px; 152 | font-size: 20px; 153 | font-weight: bold; 154 | background-color: black; 155 | color: #ffffff; 156 | text-align: left; 157 | /* float: left */ 158 | } 159 | h4 { 160 | margin: 0px; 161 | padding: 0px; 162 | font-size: 14px; 163 | font-weight: bold; 164 | } 165 | 166 | #Main_Header { 167 | background: #EEEEEE; 168 | height: 150px; 169 | width:100%; 170 | overflow:auto; 171 | } 172 | 173 | #welcome { 174 | float:left; 175 | height: 50%; 176 | width:40%; 177 | color:black; 178 | /*font-family: 'Brush Script MT', cursive;*/ 179 | font-size:7vw; 180 | display:block; 181 | white-space:nowrap; 182 | text-align:center; 183 | vertical-align:middle; 184 | 185 | } 186 | 187 | #GENFIRE_logo{ 188 | right:35%; 189 | height: 150px; 190 | overflow:auto; 191 | height: auto; 192 | } 193 | 194 | 195 | #Sidebar { 196 | position: fixed; 197 | width: 280px; 198 | height: 500px; 199 | background-color: #888888; 200 | font-size: 16px; 201 | overflow-y: scroll; 202 | top: 0; 203 | bottom: 0; 204 | right: 0; 205 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 206 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 207 | } 208 | #Sidebar .h2_sidebar{ 209 | font-size: 16px; 210 | color: #FFFFFF; 211 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 212 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 213 | } 214 | 215 | #Sidebar .h1_sidebar{ 216 | font-size: 20px; 217 | font-weight: bold; 218 | color: #222222; 219 | text-align: center; 220 | margin-bottom:15px; 221 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 222 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 223 | } 224 | 225 | #Sidebar .h2_sidebar{ 226 | font-size: 16px; 227 | color: #FFFFFF; 228 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 229 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 230 | } 231 | 232 | 233 | #Sidebar_lowered { 234 | margin-top:150px; 235 | position: fixed; 236 | width: 280px; 237 | height: 500px; 238 | background-color: #888888; 239 | font-size: 16px; 240 | overflow-y: scroll; 241 | top: 0; 242 | bottom: 0; 243 | right: 0; 244 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 245 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 246 | } 247 | #Sidebar_lowered .h2_sidebar{ 248 | font-size: 16px; 249 | color: #FFFFFF; 250 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 251 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 252 | } 253 | 254 | #Sidebar_lowered .h1_sidebar{ 255 | font-size: 20px; 256 | font-weight: bold; 257 | color: #222222; 258 | text-align: center; 259 | margin-bottom:15px; 260 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 261 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 262 | } 263 | 264 | #Sidebar_lowered .h2_sidebar{ 265 | font-size: 16px; 266 | color: #FFFFFF; 267 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 268 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 269 | } 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | .side_link{ 288 | font-size: 16px; 289 | margin-left: 15px; 290 | color:white; 291 | } 292 | -------------------------------------------------------------------------------- /documentation/make_html.txt: -------------------------------------------------------------------------------- 1 | find ../ -iname "*py" | xargs python html_helper.py 2 | find ../ -iname "*.html" | xargs -I $ mv $ ./src_html/ 3 | mv ./src_html/index.html . 4 | mv ./src_html/installation.html . 5 | mv ./src_html/GUI_parameters.html . 6 | mv ./src_html/tutorial.html . 7 | scp main.css ./src_html/main.css 8 | -------------------------------------------------------------------------------- /documentation/src_html/VolumeSlicer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//GENFIRE/gui/VolumeSlicer 6 | 7 | 8 | 9 | 10 | 11 | """
* GENFIRE.gui.VolumeSlicer *

The volume slicer module


Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""

from GENFIRE.gui import VolumeSlicer_MainWindow
from PyQt4 import QtCore, QtGui
import matplotlib
matplotlib.use("Qt4Agg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
import numpy as np
from functools import partial
from GENFIRE.gui.utility import toString, toQString, toInt, toFloat


class VolumeSlicer(QtGui.QMainWindow):
def __init__(self, volume):
super(VolumeSlicer, self).__init__()
self.volume = volume
self.ui = VolumeSlicer_MainWindow.Ui_VolumeSlicer()
self.ui.setupUi(self) # build interface

self.ui.checkBox_lockcmap.toggled.connect(self.toggleLockCmap)
self.lockColormap = False
self.ui.checkBox_lockcmap.setChecked(False)

# figures for plotting
self.fig1 = plt.figure()
self.fig2 = plt.figure()
self.fig3 = plt.figure()

# canvases link the Qt widgets with the matplotlib figures
self.canvas1 = FigureCanvas(self.fig1)
self.canvas2 = FigureCanvas(self.fig2)
self.canvas3 = FigureCanvas(self.fig3)

self.slice1 = self.fig1.add_subplot(111)
self.slice2 = self.fig2.add_subplot(111)
self.slice3 = self.fig3.add_subplot(111)

self.slice1.hold(False)
self.slice2.hold(False)
self.slice3.hold(False)

self.navigationToolbar1 = NavigationToolbar(self.canvas1, self)
self.navigationToolbar2 = NavigationToolbar(self.canvas2, self)
self.navigationToolbar3 = NavigationToolbar(self.canvas3, self)

self.ui.vt_lyt_fig1.addWidget(self.navigationToolbar1)
self.ui.vt_lyt_fig1.addWidget(self.canvas1)
self.ui.vt_lyt_fig2.addWidget(self.navigationToolbar2)
self.ui.vt_lyt_fig2.addWidget(self.canvas2)
self.ui.vt_lyt_fig3.addWidget(self.navigationToolbar3)
self.ui.vt_lyt_fig3.addWidget(self.canvas3)

dimx, dimy, dimz = np.shape(volume)
ncx, ncy, ncz = dimx//2., dimy//2, dimz//2
ncx, ncy, ncz = int(ncx), int(ncy), int(ncz)

# use of partial allows binding functions to arguments to prevent having to avoid extra parameter forwarding
self.ui.scrlbr_fig1.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr1))
self.ui.scrlbr_fig2.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr2))
self.ui.scrlbr_fig3.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr3))

self.ui.scrlbr_fig1.setValue(ncx)
self.ui.scrlbr_fig1.setMinimum(0)
self.ui.scrlbr_fig1.setMaximum(dimx-1)

self.ui.scrlbr_fig2.setValue(ncy)
self.ui.scrlbr_fig2.setMinimum(0)
self.ui.scrlbr_fig2.setMaximum(dimy-1)

self.ui.scrlbr_fig3.setValue(ncz)
self.ui.scrlbr_fig3.setMinimum(0)
self.ui.scrlbr_fig3.setMaximum(dimz-1)

self.ui.lineEdit_scrlbr1.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig1))
self.ui.lineEdit_scrlbr2.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig2))
self.ui.lineEdit_scrlbr3.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig3))

self.currentSliceX = ncx
self.currentSliceY = ncy
self.currentSliceZ = ncz
self.updateAll()

self.ui.scrlbr_fig1.valueChanged[int].connect(self.updateSliceX)
self.ui.scrlbr_fig2.valueChanged[int].connect(self.updateSliceY)
self.ui.scrlbr_fig3.valueChanged[int].connect(self.updateSliceZ)

self.clim1 = plt.getp(plt.getp(self.slice1,'images')[0],'clim')
self.clim2 = plt.getp(plt.getp(self.slice2,'images')[0],'clim')
self.clim3 = plt.getp(plt.getp(self.slice3,'images')[0],'clim')

self.lockColormap = True
self.ui.checkBox_lockcmap.setChecked(True)


def updateSliceX(self, nx):
self.slice1.imshow(np.squeeze(self.volume[nx, :, :]))
if self.lockColormap:
plt.setp(plt.getp(self.slice1,'images')[0],'clim',self.clim1)
self.canvas1.draw()

def updateSliceY(self, ny):
self.slice2.imshow(np.squeeze(self.volume[:, ny, :]))
if self.lockColormap:
plt.setp(plt.getp(self.slice2,'images')[0],'clim',self.clim2)
self.canvas2.draw()

def updateSliceZ(self, nz):
self.slice3.imshow(np.squeeze(self.volume[:, :, nz]))
if self.lockColormap:
plt.setp(plt.getp(self.slice3,'images')[0],'clim',self.clim3)
self.canvas3.draw()

def updateAll(self):
self.updateSliceX(self.currentSliceX)
self.updateSliceY(self.currentSliceY)
self.updateSliceZ(self.currentSliceZ)

def toggleLockCmap(self):
if self.ui.checkBox_lockcmap.isChecked():
self.clim1 = plt.getp(plt.getp(self.slice1,'images')[0],'clim')
self.clim2 = plt.getp(plt.getp(self.slice2,'images')[0],'clim')
self.clim3 = plt.getp(plt.getp(self.slice3,'images')[0],'clim')
self.lockColormap = True
else:
self.lockColormap = False

def setSliderFromText(self, slider, text):
slider.setValue(toInt(text))

def setTextFromSlider(self, lineedit, value):
lineedit.setText(toQString(value))
12 | -------------------------------------------------------------------------------- /documentation/src_html/__init__.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//GENFIRE/gui/__init__ 6 | 7 | 8 | 9 | 10 | 11 | from . import utility
from . import VolumeSlicer
from . import launch
from . import ProjectionCalculator
from . import GENFIRE_MainWindow
from . import ProjectionCalculator_MainWindow
from . import CalculateProjectionSeries_Dialog
from . import VolumeSlicer_MainWindow
12 | -------------------------------------------------------------------------------- /documentation/src_html/fileio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//GENFIRE/fileio 6 | 7 | 8 | 9 | 10 | 11 | """
* GENFIRE.fileio *

The primary file input/output module for GENFIRE.


Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""

import numpy as np

def readVolume(filename, order="C"):
"""
* readVolume *

Load volume into a numpy array

:param filename: filename of volume
:param order: "C" for row-major order (C-style), "F" for column-major (Fortran style)
:return:

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.

"""
import os
base, ext = os.path.splitext(filename)
if (ext == ".mrc"):
return readMRC(filename, order=order)
elif (ext == ".mat"):
return readMAT_volume(filename)
elif (ext == ".npy"):
return np.load(filename)

def readMAT_volume(filename):

#wrapper around scipy's loadmat

import numpy as np
import scipy.io
data = scipy.io.loadmat(filename)
var_name = [key for key in data if not key.startswith("__")]
if len(var_name) > 1:
raise IOError("Only 1 variable allowed per .MAT file")
else:
return np.array(data[var_name[0]])

def readNPY(filename, dtype=float, order="C"):
import numpy as np
return np.load(filename)

def readMRC(filename, dtype=float, order="C"):
"""
* readMRC *

Read in a volume in .mrc file format. See http://bio3d.colorado.edu/imod/doc/mrc_format.txt

:param filename: Filename of .mrc
:return: NumPy array containing the .mrc data

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.

"""
import numpy as np
import struct
headerIntNumber = 56
sizeof_int = 4
headerCharNumber = 800
sizeof_char = 1
with open(filename,'rb') as fid:
int_header = struct.unpack('=' + 'i'*headerIntNumber, fid.read(headerIntNumber * sizeof_int))
char_header = struct.unpack('=' + 'c'*headerCharNumber, fid.read(headerCharNumber * sizeof_char))
dimx, dimy, dimz, data_flag= int_header[:4]
if (data_flag == 0):
datatype='u1'
elif (data_flag ==1):
datatype='i1'
elif (data_flag ==2):
datatype='f4'
elif (data_flag ==3):
datatype='c'
elif (data_flag ==4):
datatype='f4'
elif (data_flag ==6):
datatype='u2'
else:
raise ValueError("No supported datatype found!\n")

return np.fromfile(file=fid, dtype=datatype,count=dimx*dimy*dimz).reshape((dimx,dimy,dimz),order=order).astype(dtype)

def writeMRC(filename, arr, datatype='f4', order="C"):
"""
* writeMRC *

Write a volume to .mrc file format. See http://bio3d.colorado.edu/imod/doc/mrc_format.txt
This version is bare-bones and doesn't write out the full header -- just the critical bits and the
volume itself

:param filename: Filename of .mrc file to write
:param arr: NumPy volume of data to write
:param dtype: Type of data to write


Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved
"""
import numpy as np

dimx, dimy, dimz = np.shape(arr)

if datatype != arr.dtype:
arr = arr.astype(datatype)
int_header = np.zeros(56,dtype='int32') #must be 4-byte ints

if (datatype == 'u1'):
data_flag = 0
elif (datatype =='i1'):
data_flag = 1
elif (datatype =='f4'):
data_flag = 2
elif (datatype =='c'):
data_flag = 3
elif (datatype =='f4'):
data_flag = 4
elif (datatype =='u2'):
data_flag = 6
else:
raise ValueError("No supported datatype found!\n")

int_header[:4] = (dimx,dimy,dimz,data_flag)
char_header = str(' '*800)
with open(filename,'wb') as fid:
fid.write(int_header.tobytes())
fid.write(char_header.encode('UTF-8'))
fid.write(arr.tobytes(order=order))


def loadProjections(filename):
"""
* loadProjections *

Wrapper function for loading in projections of arbitrary (supported) extension

:param filename: Filename of images to load
:return: NumPy array containing projections


Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""
import os
filename, file_extension = os.path.splitext(filename)
if file_extension == ".mat":
print ("Reading projections from MATLAB file.\n")
# return readMAT_projections(filename + file_extension)
return readMAT_volume(filename + file_extension)
elif file_extension == ".tif":
print ("Reading projections from .tif file.\n")
return readTIFF_projections(filename + file_extension)
elif file_extension == ".mrc":
print ("Reading projections from .mrc file.\n")
return readMRC(filename + file_extension)
elif file_extension == ".npy":
print ("Reading projections from .npy file.\n")
return readNPY(filename + file_extension)
else:
raise Exception('File format %s not supported.', file_extension)

# def readMAT_projections(filename):
# """
# * readMAT *
#
# Read projections from a .mat file
#
# :param filename: MATLAB file (.mat) containing projections
# :return: NumPy array containing projections
#
#
# Author: Alan (AJ) Pryor, Jr.
# Jianwei (John) Miao Coherent Imaging Group
# University of California, Los Angeles
# Copyright 2015-2016. All rights reserved.
# """
#
# import scipy.io
# import numpy as np
# import os
# try: #try to open the projections as a stack
# projections = scipy.io.loadmat(filename)
# key = None
# for k in projections.keys():
# if k[0] != "_":
# key = k
# break
#
# projections = np.array(projections[key])
# except: ## -- figure out where error is thrown
# #check if the projections are in individual files
# flag = True
# filename_base, file_extension = os.path.splitext(filename)
# projectionCount = 1
# while flag: #first count the number of projections so the array can be initialized
# projectionCount = projectionCount
# nextFile = filename_base + str(projectionCount) + file_extension
# if os.path.isfile(nextFile):
# projectionCount += 1
# else:
# flag = False
#
#
# ## open first projection to get dimensions
# pj = scipy.io.loadmat(filename_base + str(1) + file_extension)
# pj = pj[projections.keys()[0]]
# dims = np.shape(pj)
# #initialize projection array
# projections = np.zeros((dims[0], dims[1], projectionCount),dtype=int)
#
# #now actually load in the tiff images
# for projNum in range(projectionCount):
# nextFile = filename_base + str(projNum) + file_extension
# pj = scipy.io.loadmat(filename_base + str(projNum) + file_extension)
# pj = pj[pj.keys()[0]]
# projections[:, :, projNum] = np.array(pj)
#
# return projections


def readTIFF_projections(filename):
"""
* readTIFF *

Read (possibly multiple) TIFF images into a NumPy array

:param filename: Name of TIFF file or TIFF file basename to read. If the filename is a base then
# the images must begin with the string contained in filename followed by consecutive integers with
# no zero padding, i.e. foo1.tiff, foo2.tiff,..., foo275.tiff
:return: NumPy array containing projections

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""
import functools
from PIL import Image
import os
import numpy as np
from multiprocessing import Pool
try:
projections = np.array(Image.open(filename))
except:
flag = True
filename_base, file_extension = os.path.splitext(filename)
projectionCount = 1
while flag: #first count the number of projections so the array can be initialized
projectionCount = projectionCount
nextFile = filename_base + str(projectionCount) + file_extension
if os.path.isfile(nextFile):
projectionCount += 1
else:
flag = False

## open first projection to get dimensions
dims = np.shape(Image.open(filename_base + str(1) + file_extension))

#initialize projection array
projections = np.zeros((dims[0], dims[1], projectionCount),dtype=int)

pool = Pool(4)
func = functools.partial(readInTiffProjection, filename_base)
pj = pool.map(func, range(projectionCount))
for j in range(projectionCount):
projections[:, :, j] = pj[j]
return projections

def readInTiffProjection(filename_base, fileNumber):
"""
* readInTiffProjection *

Reads and returns a single TIFF image as a NumPy array

:param filename_base: Base filename of TIFF
:param fileNumber: Image number
:return: Image in a 2D NumPy array

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""
from PIL import Image
import numpy as np
nextFile = filename_base + str(fileNumber) + '.tif'
return np.array(Image.open(nextFile))

def loadAngles(filename):
"""
* loadAngles *

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.

:param filename:
:return:
"""
import os
base,ext = os.path.splitext(filename)
ext = ext.lower()
if ext == ".txt":
return np.loadtxt(filename,dtype=float)
elif ext== ".npy":
return np.load(filename)
elif ext==".mat":
from GENFIRE.fileio import readVolume
return readVolume(filename)
else:
raise IOError("Unsupported file extension \"{}\" for Euler angles".format(ext))


def saveResults(reconstruction_outputs, filename):
"""
* saveResults *

Helper function to save results of GENFIRE reconstruction

:param reconstruction_outputs: dictionary containing reconstruction, reciprocal error (errK), and possible R_free
:param filename: Output filename

Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved
"""
import os
fn, ext = os.path.splitext(filename)
writeVolume(filename, reconstruction_outputs['reconstruction'])
np.savetxt(fn+'_errK.txt',reconstruction_outputs['errK'])
if 'R_free_total' in reconstruction_outputs.keys():
np.savetxt(fn+'_Rfree_total.txt',reconstruction_outputs['R_free_total'])
np.savetxt(fn+'_Rfree_bybin.txt',reconstruction_outputs['R_free_bybin'])

def writeVolume(filename, data, order="C"):
"""
* writeVolume *

Wrapper volume to file

:param filename: output filename with valid extension
:param data: numpy volume to write
:param order: "C" for row-major order (C-style), "F" for column-major (Fortran style)
"""
import os
fn, ext = os.path.splitext(filename)
if ext == ".mrc":
writeMRC(filename, arr=data, order=order)
elif ext == ".npy":
import numpy as np
np.save(filename,data)
elif ext == ".mat":
import scipy.io
scipy.io.savemat(filename, {"data":data})
else:
raise IOError("Unsupported file extension \"{}\" for volume object".format(ext))
12 | -------------------------------------------------------------------------------- /documentation/src_html/html_helper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//documentation/html_helper 6 | 7 | 8 | 9 | 10 | 11 | """
bla
"""
def generate_html(filename=None):
#convert source code files into formatted html for documentation
import sys
import os
print(filename)
if not os.path.isfile(filename):
raise NameError("File Not Found")

# if filename is None and len(sys.argv)>1:
# filename=sys.argv[1]
html_filename = os.path.abspath(os.path.splitext(filename)[0]) + '.html'
header_str = """



""" + os.path.splitext(filename)[0] + """
GENFIRE Documentation">
\



\n"""

closing_str = """
"""
print("hs = {}".format(header_str))

with open(filename,'r') as fid_source:
with open(html_filename,'w') as fid:
print ("html_filename = " , html_filename)
fid.write(header_str)
fid.write("")
in_comment_flag = 0
for line in fid_source:
if line.lstrip().startswith("#"): # then this line is a single line comment and we don't format it
fid.write(line.replace('\n',"
"))
elif line.lstrip().startswith("\"\"\""): # ignore formatting on multi-line comments
fid.write(line.replace('\n',"
"))
in_comment_flag = (in_comment_flag + 1) % 2
elif in_comment_flag:
fid.write(line.replace('\n',"
"))
else:
inline_comment_start = line.find("#")
if inline_comment_start == -1: # no inline comment
fid.write(code_formatter(line))
else:
fid.write(code_formatter(line[:inline_comment_start].replace('\n',"
")))
fid.write(line[inline_comment_start:].replace('\n',"
"))
fid.write("
")
fid.write(closing_str)

def code_formatter(string):
# A simple custom HTML code formatter that colors some keywords and tries to avoid instances of them within comments
color_string = "\"orange\""
keywords = ["from", "def","class", "self", "__main__", "for", "if",\
"while","import","else","elif", "True","False", "del", \
"with", "plt", "QtCore", "QtGui", "Qt", "ui"]
short_keywords = keywords[:]
new_keywords = []
for i, v in enumerate(keywords):
keywords[i] = v + " "
new_keywords.append(v + ".")
new_keywords.append(v + "\n")
keywords += new_keywords
format_string = ("", "")
replacers={}

for kw in keywords:
replacers[kw] = format_string

GENFIRE_format_string = ("", "")
replacers['GENFIRE'] = GENFIRE_format_string
replacers['genfire'] = GENFIRE_format_string



# replacers={"from":("", "")}



string = string.replace('\t', "    ")
if replacers is not None:
for key, value in replacers.iteritems():
# print (key, value)
string = string.replace(key,value[0] + key + value[1])

# for key in short_keywords:
# if string.endswith(key):
# string.replace(key, ("" + key+ "") )
string = string.replace('\n',"
")
return string

if __name__=="__main__":
import sys
if len(sys.argv) > 1:
for j in range(1,len(sys.argv)):
generate_html(sys.argv[j])
else:
generate_html("html_helper.py")
12 | -------------------------------------------------------------------------------- /documentation/src_html/main.css: -------------------------------------------------------------------------------- 1 | #bounding_box { 2 | width:85%; 3 | padding = 14px 40px; 4 | text-align:justify; 5 | overflow-x: scroll; 6 | } 7 | h1 { 8 | margin: 10px; 9 | padding: 14px 0px; 10 | font-size: 36px; 11 | font-weight: bold; 12 | background-color: black; 13 | color: #ffffff; 14 | text-align: center 15 | } 16 | .h1_left { 17 | margin: 10px; 18 | padding: 14px 0px; 19 | font-size: 36px; 20 | font-weight: bold; 21 | color: #ffffff; 22 | background-color: black; 23 | 24 | text-align: left; 25 | } 26 | 27 | 28 | body { 29 | margin: 0; 30 | padding: 0; 31 | line-height: 1.5em; 32 | font-family: Arial, Helvetica, sans-serif; 33 | font-size: 16px; 34 | color: #AAAAAA; 35 | background: #080808; 36 | background: black; 37 | overflow-x: scroll; 38 | 39 | } 40 | 41 | a:link, a:visited { 42 | color: #ff6600; 43 | color:orange; 44 | text-decoration: none; 45 | font-weight: normal; 46 | } 47 | 48 | a:active, a:hover{ 49 | color: #FFCC00; 50 | color:orange; 51 | text-decoration: underline; 52 | } 53 | 54 | p { 55 | margin: 10px; 56 | margin-right:155px; 57 | padding: 0px; 58 | text-align:justify; 59 | } 60 | 61 | ul{ 62 | margin: 10px; 63 | margin-right:155px; 64 | padding: 15px; 65 | text-align:justify; 66 | } 67 | 68 | .code_box{ 69 | width: 85%; 70 | text-align: justify; 71 | } 72 | .code { 73 | height:150%; 74 | /* margin-left:500px; */ 75 | margin-top:100px; 76 | background:#666666; 77 | color:orange; 78 | margin: 25px 25px 25px 25px; 79 | /* margin-right:155px; */ 80 | /* margin:0 auto; */ 81 | padding: 15; 82 | text-align:justify; 83 | width:1000px; 84 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 85 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 86 | } 87 | 88 | 89 | img { 90 | margin: 0px; 91 | padding: 30px; 92 | border: none; 93 | } 94 | 95 | h2 { 96 | position: relative; 97 | height: 25px; 98 | margin: 0px; 99 | padding: 10px 0 0 0; 100 | font-size: 20px; 101 | font-weight: bold; 102 | text-align: left; 103 | color: #000000; 104 | color:white 105 | } 106 | 107 | 108 | h3 { 109 | margin: 0 0 5px 0; 110 | padding: 2px 0 3px 0; 111 | font-size: 14px; 112 | font-weight: normal; 113 | color: #d7e13d; 114 | color: orange; 115 | border-bottom: 1px dotted #d7e13d; 116 | } 117 | 118 | .h2_left { 119 | margin-left:10px; 120 | font-size: 24px; 121 | font-weight: bold; 122 | background-color: black; 123 | color: #ffffff; 124 | text-align: left; 125 | text-decoration:underline; 126 | /* float: left */ 127 | } 128 | .h2_center { 129 | margin-left:10px; 130 | font-size: 42px; 131 | padding-top: 10px; 132 | padding-bottom: 10px; 133 | font-weight: bold; 134 | background-color: black; 135 | color: #ffffff; 136 | text-align: center; 137 | text-decoration:underline; 138 | /* float: left */ 139 | } 140 | .h3_left { 141 | margin-left:10px; 142 | font-size: 20px; 143 | font-weight: bold; 144 | background-color: black; 145 | color: #ffffff; 146 | text-align: left; 147 | text-decoration:/* underline */; 148 | /* float: left */ 149 | } 150 | .h5_left { 151 | margin-left:10px; 152 | font-size: 20px; 153 | font-weight: bold; 154 | background-color: black; 155 | color: #ffffff; 156 | text-align: left; 157 | /* float: left */ 158 | } 159 | h4 { 160 | margin: 0px; 161 | padding: 0px; 162 | font-size: 14px; 163 | font-weight: bold; 164 | } 165 | 166 | #Main_Header { 167 | background: #EEEEEE; 168 | height: 150px; 169 | width:100%; 170 | overflow:auto; 171 | } 172 | 173 | #welcome { 174 | float:left; 175 | height: 50%; 176 | width:40%; 177 | color:black; 178 | /*font-family: 'Brush Script MT', cursive;*/ 179 | font-size:7vw; 180 | display:block; 181 | white-space:nowrap; 182 | text-align:center; 183 | vertical-align:middle; 184 | 185 | } 186 | 187 | #GENFIRE_logo{ 188 | right:35%; 189 | height: 150px; 190 | overflow:auto; 191 | height: auto; 192 | } 193 | 194 | 195 | #Sidebar { 196 | position: fixed; 197 | width: 280px; 198 | height: 500px; 199 | background-color: #888888; 200 | font-size: 16px; 201 | overflow-y: scroll; 202 | top: 0; 203 | bottom: 0; 204 | right: 0; 205 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 206 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 207 | } 208 | #Sidebar .h2_sidebar{ 209 | font-size: 16px; 210 | color: #FFFFFF; 211 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 212 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 213 | } 214 | 215 | #Sidebar .h1_sidebar{ 216 | font-size: 20px; 217 | font-weight: bold; 218 | color: #222222; 219 | text-align: center; 220 | margin-bottom:15px; 221 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 222 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 223 | } 224 | 225 | #Sidebar .h2_sidebar{ 226 | font-size: 16px; 227 | color: #FFFFFF; 228 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 229 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 230 | } 231 | 232 | 233 | #Sidebar_lowered { 234 | margin-top:150px; 235 | position: fixed; 236 | width: 280px; 237 | height: 500px; 238 | background-color: #888888; 239 | font-size: 16px; 240 | overflow-y: scroll; 241 | top: 0; 242 | bottom: 0; 243 | right: 0; 244 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 245 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 246 | } 247 | #Sidebar_lowered .h2_sidebar{ 248 | font-size: 16px; 249 | color: #FFFFFF; 250 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 251 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 252 | } 253 | 254 | #Sidebar_lowered .h1_sidebar{ 255 | font-size: 20px; 256 | font-weight: bold; 257 | color: #222222; 258 | text-align: center; 259 | margin-bottom:15px; 260 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 261 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 262 | } 263 | 264 | #Sidebar_lowered .h2_sidebar{ 265 | font-size: 16px; 266 | color: #FFFFFF; 267 | box-shadow: inset 0 -2px 2px rgba(0,0,0,0.5), /*bottom internal shadow*/ 268 | inset 0 2px 2px rgba(255,255,255,1); /*top internal highlight*/ 269 | } 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | .side_link{ 288 | font-size: 16px; 289 | margin-left: 15px; 290 | color:white; 291 | } 292 | -------------------------------------------------------------------------------- /documentation/src_html/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//GENFIRE/main 6 | 7 | 8 | 9 | 10 | 11 | """
* GENFIRE.main *

The primary control module for running GENFIRE reconstructions.


Author: Alan (AJ) Pryor, Jr.
Jianwei (John) Miao Coherent Imaging Group
University of California, Los Angeles
Copyright 2015-2016. All rights reserved.
"""

from __future__ import division
import numpy as np
import GENFIRE
import sys
import os
from GENFIRE.reconstruct import ReconstructionParameters


def main_InteractivelySetParameters():
#######################################################################################################################
############################################### User Parameters ######################################################
#######################################################################################################################

# GENFIRE's reconstruction parameters can be edited here by the user and run interactively, any inputs provided
# by either the command line or the GUI will override these momentarily

filename_projections = '../data/projections.mat' #filename of projections, which should be size NxNxN_projections where N_projections is the number of projections
filename_angles = '../data/angles.mat' #angles can be either a 1xN_projections array containing a single tilt series, or 3xN_projections array containing 3 Euler angles for each projections in the form [phi;theta;psi]
filename_support = '../data/support60.mat' #NxNxN binary array specifying a region of 1's in which the reconstruction can exist
filename_initialObject = None #initial object to use in reconstruction; set to None to provide no initial guess
filename_results = 'GENFIRE_rec.mrc' #filename to save results
resolutionExtensionSuppressionState = 2 # 1) Turn on resolution extension/suppression, 2) No resolution extension/suppression, 3) Just resolution extension

numIterations = 100 #number of iterations to run in iterative reconstruction
oversamplingRatio = 3 #input projections will be padded internally to match this oversampling ratio. If you prepad your projections, set this to 1
interpolationCutoffDistance = 0.7 #radius of spherical interpolation kernel (in pixels) within which to include measured datapoints
doYouWantToDisplayFigure = True
displayFigure = GENFIRE.reconstruct.DisplayFigure()
displayFigure.DisplayFigureON = doYouWantToDisplayFigure
calculateRFree = True
if filename_support is None:
useDefaultSupport = True
else:
useDefaultSupport = False

reconstruction_parameters = ReconstructionParameters()
reconstruction_parameters.projectionFilename = filename_projections
reconstruction_parameters.angleFilename = filename_angles
reconstruction_parameters.supportFilename = filename_support
reconstruction_parameters.interpolationCutoffDistance = interpolationCutoffDistance
reconstruction_parameters.numIterations = numIterations
reconstruction_parameters.oversamplingRatio = oversamplingRatio
reconstruction_parameters.displayFigure = displayFigure
reconstruction_parameters.calculateRfree = calculateRFree
reconstruction_parameters.resolutionExtensionSuppressionState = resolutionExtensionSuppressionState
reconstruction_parameters.useDefaultSupport = useDefaultSupport
if os.path.isfile(filename_results): # If a valid initial object was provided, use it
reconstruction_parameters.initialObjectFilename = filename_results

main(reconstruction_parameters)

def main(reconstruction_parameters):
import GENFIRE.fileio

filename_projections = reconstruction_parameters.projectionFilename
filename_angles = reconstruction_parameters.angleFilename
filename_support = reconstruction_parameters.supportFilename
filename_results = reconstruction_parameters.resultsFilename
numIterations = reconstruction_parameters.numIterations
oversamplingRatio = reconstruction_parameters.oversamplingRatio
interpolationCutoffDistance = reconstruction_parameters.interpolationCutoffDistance
displayFigure = reconstruction_parameters.displayFigure
resolutionExtensionSuppressionState = reconstruction_parameters.resolutionExtensionSuppressionState
calculateRFree = reconstruction_parameters.calculateRfree
useDefaultSupport = reconstruction_parameters.useDefaultSupport
use_positivity = reconstruction_parameters.constraint_positivity
use_support = reconstruction_parameters.constraint_support
gridding_method = reconstruction_parameters.griddingMethod
enforceResolutionCircle = reconstruction_parameters.enforceResolutionCircle
permitMultipleGridding = reconstruction_parameters.permitMultipleGridding

if reconstruction_parameters.isInitialObjectDefined:
filename_initialObject = reconstruction_parameters.initialObjectFilename
else:
filename_initialObject = None

### begin reconstruction ###
projections = GENFIRE.fileio.loadProjections(filename_projections) # load projections into a 3D numpy array

# get dimensions of array and determine the array size after padding
dims = np.shape(projections)
paddedDim = dims[0] * oversamplingRatio
padding = int((paddedDim-dims[0])/2)

# load the support, or generate one if none was provided
if useDefaultSupport or filename_support == "":
support = np.ones((dims[0],dims[0],dims[0]),dtype=float)
else:
support = (GENFIRE.fileio.readVolume(filename_support) != 0).astype(bool)

displayFigure.reconstructionDisplayWindowSize = np.shape(support) # this is used to show the central region of reconstruction

# now zero-pad to match the oversampling ratio
support = np.pad(support,((padding,padding),(padding,padding),(padding,padding)),'constant')
projections = np.pad(projections,((padding,padding),(padding,padding),(0,0)),'constant')

#load initial object, or initialize it to zeros if none was given
if filename_initialObject is not None and os.path.isfile(filename_initialObject):
initialObject = GENFIRE.fileio.readVolume(filename_initialObject)
initialObject = np.pad(initialObject,((padding,padding),(padding,padding),(padding,padding)),'constant')
else:
initialObject = np.zeros_like(support)

# load angles and check that the dimensions match the number of provided projections and that they
# are either 1 x num_projections or 3 x num_projections
angles = GENFIRE.fileio.loadAngles(filename_angles)
if np.shape(angles)[1] > 3:
raise ValueError("Error! Dimension of angles incorrect.")
if np.shape(angles)[1] == 1:
tmp = np.zeros([np.shape(angles)[1], 3])
tmp[1, :] = angles
angles = tmp
del tmp

# grid the projections
if gridding_method == "DFT":
measuredK = GENFIRE.reconstruct.fillInFourierGrid_DFT(projections, angles, interpolationCutoffDistance, enforceResolutionCircle)
else:
measuredK = GENFIRE.reconstruct.fillInFourierGrid(projections, angles, interpolationCutoffDistance, enforceResolutionCircle, permitMultipleGridding)

# the grid is assembled with the origin at the geometric center of the array, but for efficiency in the
# iterative algorithm the origin is shifted to array position [0,0,0] to avoid unnecessary fftshift calls
measuredK = np.fft.ifftshift(measuredK)

# create a map of the spatial frequency to be used to control resolution extension/suppression behavior
K_indices = GENFIRE.utility.generateKspaceIndices(support)
K_indices = np.fft.fftshift(K_indices)
resolutionIndicators = np.zeros_like(K_indices)
resolutionIndicators[measuredK != 0] = 1-K_indices[measuredK != 0]

# if calculating Rfree, setup some infrastructure
if calculateRFree:
R_freeInd_complexX = []
R_freeInd_complexY = []
R_freeInd_complexZ = []
R_freeVals_complex = []
shell_thickness_pixels = 1 # pixel thickness of an individual shell of Rfree points
numberOfBins = int(round(dims[0]/2/shell_thickness_pixels)) # number of frequency bins. Rfree will be tracked within each shell separately
percentValuesForRfree = 0.05 # percentage of measured points to withhold
spatialFrequencyForRfree = np.linspace(0,1,numberOfBins+1)
K_indicesSmall =(K_indices)[:, :, 0:(np.shape(measuredK)[-1]//2+1)]

for shellNum in range(0,numberOfBins):
# collect relevant points
measuredPointInd_complex = np.where((measuredK[:, :, 0:(np.shape(measuredK)[-1]//2+1)] != 0) & (K_indicesSmall>=(spatialFrequencyForRfree[shellNum])) & (K_indicesSmall<=(spatialFrequencyForRfree[shellNum+1])))

# randomly shuffle
shuffledPoints = np.random.permutation(np.shape(measuredPointInd_complex)[1])
measuredPointInd_complex = (measuredPointInd_complex[0][shuffledPoints], measuredPointInd_complex[1][shuffledPoints], measuredPointInd_complex[2][shuffledPoints])

# determine how many values to take
cutoffInd_complex = np.floor(np.shape(measuredPointInd_complex)[1] * percentValuesForRfree).astype(int)

# collect the Rfree values and coordinates
R_freeInd_complexX.append(measuredPointInd_complex[0][:cutoffInd_complex])
R_freeInd_complexY.append(measuredPointInd_complex[1][:cutoffInd_complex])
R_freeInd_complexZ.append(measuredPointInd_complex[2][:cutoffInd_complex])
R_freeVals_complex.append(measuredK[R_freeInd_complexX[shellNum], R_freeInd_complexY[shellNum], R_freeInd_complexZ[shellNum] ])

# delete the points from the measured data
measuredK[R_freeInd_complexX[shellNum], R_freeInd_complexY[shellNum], R_freeInd_complexZ[shellNum]] = 0

# create tuple of coordinates
R_freeInd_complex = [[R_freeInd_complexX], [R_freeInd_complexY], [R_freeInd_complexZ]]
del R_freeInd_complexX
del R_freeInd_complexY
del R_freeInd_complexZ
else:
R_freeInd_complex = []
R_freeVals_complex = []

if resolutionExtensionSuppressionState==1: # resolution extension/suppression
constraintEnforcementDelayIndicators = np.array(np.concatenate((np.arange(0.95, -.25, -0.15), np.arange(-0.15, .95, .1)), axis=0))
elif resolutionExtensionSuppressionState==2:# no resolution extension or suppression
constraintEnforcementDelayIndicators = np.array([-999, -999, -999, -999])
elif resolutionExtensionSuppressionState==3:# resolution extension only
constraintEnforcementDelayIndicators = np.concatenate((np.arange(0.95, -.15, -0.15),[-0.15, -0.15, -0.15]))
else:
print("Warning! Input resolutionExtensionSuppressionState does not match an available option. Deactivating dynamic constraint enforcement and continuing.\n")
constraintEnforcementDelayIndicators = np.array([-999, -999, -999, -999])

reconstructionOutputs = GENFIRE.reconstruct.reconstruct(numIterations, np.fft.fftshift(initialObject), np.fft.fftshift(support), (measuredK)[:, :, 0:(np.shape(measuredK)[-1] // 2 + 1)], (resolutionIndicators)[:, :, 0:(np.shape(measuredK)[-1] // 2 + 1)], constraintEnforcementDelayIndicators, R_freeInd_complex, R_freeVals_complex, displayFigure, use_positivity, use_support)

# reclaim original array size. ncBig is center of oversampled array, and n2 is the half-width of original array
ncBig = paddedDim//2
n2 = dims[0]//2
reconstructionOutputs['reconstruction'] = reconstructionOutputs['reconstruction'][ncBig-n2:ncBig+n2,ncBig-n2:ncBig+n2,ncBig-n2:ncBig+n2]
GENFIRE.fileio.saveResults(reconstructionOutputs, filename_results)

if __name__ == "__main__" and len(sys.argv) == 1:
print ("starting with user parameters")
main_InteractivelySetParameters()
elif __name__ == "__main__":
if len(sys.argv) > 1: # Parse inputs provided either from the GUI or from the command line
inputArgumentOptions = {"-p" : "filename_projections",
"-a" : "filename_angles",
"-s" : "filename_support",
"-o" : "filename_results",
"-i" : "filename_initialObject",
"-r" : "resolutionExtensionSuppressionState",
"-it": "numIterations",
"-or": "oversamplingRatio",
"-t" : "interpolationCutoffDistance",
"-d" : "displayFigure",
"-rf": "calculateRFree"
}
print (sys.argv[:])
if len(sys.argv)%2==0:
raise Exception("Number of input options and input arguments does not match!")
for argumentNum in range(1,len(sys.argv),2):
print (inputArgumentOptions[sys.argv[argumentNum]])
print (sys.argv[argumentNum+1])
print (inputArgumentOptions[sys.argv[argumentNum]] + "=" + sys.argv[argumentNum+1])


exec(inputArgumentOptions[sys.argv[argumentNum]] + "= '" + sys.argv[argumentNum+1] +"'")
print("Setting argument %s from option %s equal to GENFIRE parameter %s " % (sys.argv[argumentNum+1],sys.argv[argumentNum], inputArgumentOptions[sys.argv[argumentNum]] ))

numIterations = int(numIterations)
# displayFigure = bool(displayFigure)
doYouWantToDisplayFigure = bool(displayFigure)
displayFigure = GENFIRE.reconstruct.DisplayFigure()
displayFigure.DisplayFigureON = doYouWantToDisplayFigure
oversamplingRatio = float(oversamplingRatio)
resolutionExtensionSuppressionState = int(resolutionExtensionSuppressionState)
calculateRFree = bool(calculateRFree)
try:
main(filename_projections,
filename_angles,
filename_support,
filename_results,
numIterations,
oversamplingRatio,
interpolationCutoffDistance,
resolutionExtensionSuppressionState,
displayFigure,
calculateRFree,
filename_initialObject)
except (NameError, IOError):
main(filename_projections,
filename_angles,
filename_support,
filename_results,
numIterations,
oversamplingRatio,
interpolationCutoffDistance,
resolutionExtensionSuppressionState,
displayFigure,
calculateRFree)
12 | -------------------------------------------------------------------------------- /documentation/src_html/projections.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/documentation/src_html/projections.html -------------------------------------------------------------------------------- /documentation/src_html/setup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ..//setup 6 | 7 | 8 | 9 | 10 | 11 | from setuptools import find_packages,setup, Extension
from subprocess import call

setup(
    name                 = "GENFIRE",
    packages         = find_packages(),
    version             = "1.0",
    description         = "GENeralized Fourier Iterative REconstruction",
    author                 = "Alan (AJ) Pryor, Jr.",
author_email         = "apryor6@gmail.com",
install_requires    = ['Pillow','numpy','matplotlib','scipy', 'pyparsing','six'],
    scripts                = ['bin/genfire']
)


12 | -------------------------------------------------------------------------------- /documentation/tutorial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GENFIRE Tutorial 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 40 | 41 | 42 | 43 |

Tutorial

44 |

45 | This tutorial will walk you through your first GENFIRE 3D reconstruction. You will 46 | simulate a reconstruction of a tomographically-acquired tilt series using a vesicle model 47 | with GENFIRE's GUI. 48 |

49 | 50 |

51 | First thing's first -- open the GUI. It looks like this 52 |

53 |
GENFIRE GUI
54 |

55 | This is the main window for running GENFIRE reconstructions. Here you can select the filenames 56 | containing the projection images, Euler angles, 3D support and set reconstruction parameters 57 | like the number of iterations to run and the oversampling ratio (the amount of zero padding to add 58 | to the projections prior to gridding). First we have to create a simulated dataset so that we have 59 | something to work with. For that we can use the projection calculator, which can be accessed from a drop-down menu at the top of the screen: 60 |

61 |

62 | Projection Calculator -> Launch Projection Calculator 63 |

64 |

65 | You should now have a blank instance of the projection calculator, like this: 66 |

67 |
The GENFIRE Projection Calculator Module 69 |

70 | Now we need to select a 3D model. Click Browse, find "vesicle.mrc" in the data 71 | directory of the GENFIRE source code, then click open. You will be prompted to select 72 | an oversampling ratio. The oversampling ratio controls the amount of zero padding applied 73 | to the model -- specifically the oversampling ratio is the total array size divided 74 | by the size of the object. The purpose of this zero-padding is to increase the accuracy 75 | of the projection calculation. The tradeoff is that larger oversampling ratios mean the 76 | array size is bigger, and, therefore, slower. I find that an oversampling ratio of 3 77 | is a good choice. Click OK, and GENFIRE will load the model, pad it, 78 | compute the 3D FFT, and construct a linear interpolator. Once finished projections 79 | may be calculated relatively quickly. 80 |

81 | 82 |

83 | Once loaded the zero-degree projection of the model will appear in the display. 84 |

85 |
The GENFIRE Projection Calculator Module with Model 87 |

88 | At this point you can adjust the Euler angles to explore what different views of the 89 | model look like. Note that these are projection images, not surface renderings. If you 90 | are new to tomography, take a moment to explore how the projection images change as you 91 | adjust the angles, in particular theta. This can give you some really nice intuition as 92 | to how 3D information is encoded in the 2D projection series.
93 | Once you are ready, calculate a projection image dataset from this model by clicking "Calculate Projection 94 | Series from Model" 95 |

96 |
Dialog to specify Euler angles -- empty 98 |

99 | From this dialog you can specify the Euler angles for each of the calculated projections. 100 | To accomplish this you have two options. 101 |

102 |

103 | The first is to provide the Euler angles as a space-delimited .txt file where each 104 | row corresponds to one projection and provides the Euler angles as phi theta psi. 105 | If you are confused about this format you can view the outputted file with option 2 to see an example. 106 | Note there is no limitation on the angles for GENFINRE like there are in many single-axis tomography 107 | reconstruction techniques, so you can use whatever you'd like. 108 |

109 |

110 | The second option is to specify a single-axis tilt series. Specify the tilt angle, theta, 111 | as start = 0, step = 2, stop = 180 to calculate 91 equally spaced projections with no missing wedge. 112 | Choose an output filename for the projection, make sure "Save Angles" is checked, 113 | then click "Calculate Projections" to perform the calculation. 114 |

115 |
Dialog to specify Euler angles -- ready 117 |

118 | The calculation runs in the background on a separate thread. Once it is finished you will hopefully see 119 | a success message like this 120 |

121 |
GENFIRE GUI ready to reconstruct 123 |

124 | Note that the file created containing the Euler angles is the same name as the corresponding 125 | projections with "_euler_angles" appended, in case you want an example of how to format 126 | your own angle files. 127 |

128 |

129 | For now, we will just use the default reconstruction parameters (more detail is given on them HERE). 130 | Verify that the filenames of your data are correct, then start the reconstruction 131 | by clicking the enormous green button. 132 |

133 |
Reconstruction finished! 134 |

135 | Congratulations, you have completed your first GENFIRE reconstruction! You can now view 136 | the error curves and a simple visualization of the results by clicking "Summarize Results" 137 | and selecting the file with your results. 138 |

139 |
Summary of results! 141 |

142 | What's all this, you ask?

143 | The left figure shows projection images of the reconstruction along the 3 principal 144 | axes and central slices. You'll be able to visualize the volume more closely in a moment. 145 | The top error curve plots the total reciprocal error vs iteration number. This is the R-factor 146 | between the FFT of the reconstruction and the entire constraint set. By default the reconstruction 147 | is performed using resolution extension/suppression, so for the early iterations only the lowest 148 | resolution constraints are enforced, but the error is still compared to all constraints so there 149 | are dips each time the constraint set is updated. This style of constraint enforcement is useful 150 | for noisy data -- here we have a noiseless simulation so you won't see much difference in the 151 | reconstruction if you turn it off.

152 | The middle and bottom curves summarize the results for R-free. GENFIRE implements a modified version 153 | of the concept of R-free from X-ray crystallography. First, the constraint set is divided up into 154 | bins (10 by default). In each spatial frequency bin, 5% of the values are withheld from the reconstruction. 155 | At each iteration, the R-factor is calculated between the voxels in reciprocal space and these withheld values. 156 | The purpose of this is a metric for prevention of overfitting to the data. Low values of R-free indicate 157 | that recovered values for missing datapoints match the (withheld) input data, and by extension 158 | suggests confidence in reconstructed values where there is no measured datapoint to compare.

159 | The middle curve shows the mean value of R-free across all resolutions at each iteration. For clean 160 | data it will generally mirror the reciprocal error curve. The bottom curve shows the value of R-free for 161 | each spatial frequency bin at the final iteration. It generally increases with spatial frequency. For this 162 | noiseless simulation the values are quite low, but for noisy data R-free will be higher. It is important 163 | to remember that high values of R-free are not necessarily bad, they simply mean there is difference between 164 | the recovered and measured reciprocal-space data. For noisy data this may be what you want, as resolution 165 | extension/suppression can act as a denoising technique. However, R-free will also be high if your data 166 | is not good. This illustrates the importance of considering multiple metrics when drawing conclusions about 167 | your results. Remember - "Garbage in, garbage out". 168 |

169 |

170 | To explore your reconstruction, open the volume slicer
171 | Volume Slicer -> Launch Volume Slicer
172 | and select your results. 173 |

174 |
Volume Slicer! 176 |

177 | Here you can view individual layers of your reconstruction (or any volume) along the 3 principal directions. 178 | You can also use this module to view your calculated projections. 179 |

180 |

181 | Hopefully this tutorial has been helpful. Happy reconstructing! 182 |

183 | 184 |
185 | 186 | 187 | -------------------------------------------------------------------------------- /genfire/__init__.py: -------------------------------------------------------------------------------- 1 | from . import utility 2 | from . import reconstruct 3 | from . import fileio 4 | from . import gui 5 | -------------------------------------------------------------------------------- /genfire/fileio.py: -------------------------------------------------------------------------------- 1 | """ 2 | * genfire.fileio * 3 | 4 | The primary file input/output module for GENFIRE. 5 | 6 | 7 | Author: Alan (AJ) Pryor, Jr. 8 | Jianwei (John) Miao Coherent Imaging Group 9 | University of California, Los Angeles 10 | Copyright 2015-2016. All rights reserved. 11 | """ 12 | 13 | import numpy as np 14 | 15 | def readVolume(filename, order="C"): 16 | """ 17 | * readVolume * 18 | 19 | Load volume into a numpy array 20 | 21 | :param filename: filename of volume 22 | :param order: "C" for row-major order (C-style), "F" for column-major (Fortran style) 23 | :return: 24 | 25 | Author: Alan (AJ) Pryor, Jr. 26 | Jianwei (John) Miao Coherent Imaging Group 27 | University of California, Los Angeles 28 | Copyright 2015-2016. All rights reserved. 29 | 30 | """ 31 | import os 32 | base, ext = os.path.splitext(filename) 33 | if (ext == ".mrc"): 34 | return readMRC(filename, order=order) 35 | elif (ext == ".mat"): 36 | return readMAT_volume(filename) 37 | elif (ext == ".npy"): 38 | return np.load(filename) 39 | 40 | def readMAT_volume(filename): 41 | 42 | #wrapper around scipy's loadmat 43 | 44 | import numpy as np 45 | import scipy.io 46 | data = scipy.io.loadmat(filename) 47 | var_name = [key for key in data if not key.startswith("__")] 48 | if len(var_name) > 1: 49 | raise IOError("Only 1 variable allowed per .MAT file") 50 | else: 51 | return np.array(data[var_name[0]]) 52 | 53 | def readNPY(filename, dtype=float, order="C"): 54 | import numpy as np 55 | return np.load(filename) 56 | 57 | def readMRC(filename, dtype=float, order="C"): 58 | """ 59 | * readMRC * 60 | 61 | Read in a volume in .mrc file format. See http://bio3d.colorado.edu/imod/doc/mrc_format.txt 62 | 63 | :param filename: Filename of .mrc 64 | :return: NumPy array containing the .mrc data 65 | 66 | Author: Alan (AJ) Pryor, Jr. 67 | Jianwei (John) Miao Coherent Imaging Group 68 | University of California, Los Angeles 69 | Copyright 2015-2016. All rights reserved. 70 | 71 | """ 72 | import numpy as np 73 | import struct 74 | headerIntNumber = 56 75 | sizeof_int = 4 76 | headerCharNumber = 800 77 | sizeof_char = 1 78 | with open(filename,'rb') as fid: 79 | int_header = struct.unpack('=' + 'i'*headerIntNumber, fid.read(headerIntNumber * sizeof_int)) 80 | char_header = struct.unpack('=' + 'c'*headerCharNumber, fid.read(headerCharNumber * sizeof_char)) 81 | dimx, dimy, dimz, data_flag= int_header[:4] 82 | if (data_flag == 0): 83 | datatype='u1' 84 | elif (data_flag ==1): 85 | datatype='i1' 86 | elif (data_flag ==2): 87 | datatype='f4' 88 | elif (data_flag ==3): 89 | datatype='c' 90 | elif (data_flag ==4): 91 | datatype='f4' 92 | elif (data_flag ==6): 93 | datatype='u2' 94 | else: 95 | raise ValueError("No supported datatype found!\n") 96 | 97 | return np.fromfile(file=fid, dtype=datatype,count=dimx*dimy*dimz).reshape((dimx,dimy,dimz),order=order).astype(dtype) 98 | 99 | def writeMRC(filename, arr, datatype='f4', order="C", pixel_size=1): 100 | """ 101 | * writeMRC * 102 | 103 | Write a volume to .mrc file format. See http://bio3d.colorado.edu/imod/doc/mrc_format.txt 104 | This version is bare-bones and doesn't write out the full header -- just the critical bits and the 105 | volume itself 106 | 107 | :param filename: Filename of .mrc file to write 108 | :param arr: NumPy volume of data to write 109 | :param dtype: Type of data to write 110 | 111 | 112 | Author: Alan (AJ) Pryor, Jr. 113 | Jianwei (John) Miao Coherent Imaging Group 114 | University of California, Los Angeles 115 | Copyright 2015-2016. All rights reserved 116 | """ 117 | import numpy as np 118 | 119 | dimx, dimy, dimz = np.shape(arr) 120 | 121 | if datatype != arr.dtype: 122 | arr = arr.astype(datatype) 123 | # int_header = np.zeros(56,dtype='int32') #must be 4-byte ints 124 | int_header1 = np.zeros(10,dtype='int32') #must be 4-byte ints 125 | float_header1 = np.zeros(6,dtype='float32') #must be 4-byte ints 126 | int_header2 = np.zeros(3,dtype='int32') #must be 4-byte ints 127 | float_header2 = np.zeros(3,dtype='float32') #must be 4-byte ints 128 | int_header3 = np.zeros(34,dtype='int32') #must be 4-byte ints 129 | 130 | 131 | if (datatype == 'u1'): 132 | data_flag = 0 133 | elif (datatype =='i1'): 134 | data_flag = 1 135 | elif (datatype =='f4'): 136 | data_flag = 2 137 | elif (datatype =='c'): 138 | data_flag = 3 139 | elif (datatype =='f4'): 140 | data_flag = 4 141 | elif (datatype =='u2'): 142 | data_flag = 6 143 | else: 144 | raise ValueError("No supported datatype found!\n") 145 | int_header1[:4] = (dimx,dimy,dimz,data_flag) 146 | int_header1[7:10] = (dimx,dimy,dimz) 147 | float_header1[:3] = (pixel_size * dimx, pixel_size * dimy, pixel_size * dimz) 148 | int_header2[:3] = (1, 2, 3) 149 | float_header2[:3] = np.min(arr), np.max(arr), np.mean(arr) 150 | char_header = str(' '*800) 151 | with open(filename,'wb') as fid: 152 | fid.write(int_header1.tobytes()) 153 | fid.write(float_header1.tobytes()) 154 | fid.write(int_header2.tobytes()) 155 | fid.write(float_header2.tobytes()) 156 | fid.write(int_header3.tobytes()) 157 | fid.write(char_header.encode('UTF-8')) 158 | fid.write(arr.tobytes(order=order)) 159 | 160 | 161 | def loadProjections(filename): 162 | """ 163 | * loadProjections * 164 | 165 | Wrapper function for loading in projections of arbitrary (supported) extension 166 | 167 | :param filename: Filename of images to load 168 | :return: NumPy array containing projections 169 | 170 | 171 | Author: Alan (AJ) Pryor, Jr. 172 | Jianwei (John) Miao Coherent Imaging Group 173 | University of California, Los Angeles 174 | Copyright 2015-2016. All rights reserved. 175 | """ 176 | import os 177 | filename, file_extension = os.path.splitext(filename) 178 | if file_extension == ".mat": 179 | return readMAT_volume(filename + file_extension) 180 | elif file_extension == ".tif": 181 | return readTIFF_projections(filename + file_extension) 182 | elif file_extension == ".mrc": 183 | return readMRC(filename + file_extension) 184 | elif file_extension == ".npy": 185 | return readNPY(filename + file_extension) 186 | else: 187 | raise Exception('File format %s not supported.', file_extension) 188 | 189 | # def readMAT_projections(filename): 190 | # """ 191 | # * readMAT * 192 | # 193 | # Read projections from a .mat file 194 | # 195 | # :param filename: MATLAB file (.mat) containing projections 196 | # :return: NumPy array containing projections 197 | # 198 | # 199 | # Author: Alan (AJ) Pryor, Jr. 200 | # Jianwei (John) Miao Coherent Imaging Group 201 | # University of California, Los Angeles 202 | # Copyright 2015-2016. All rights reserved. 203 | # """ 204 | # 205 | # import scipy.io 206 | # import numpy as np 207 | # import os 208 | # try: #try to open the projections as a stack 209 | # projections = scipy.io.loadmat(filename) 210 | # key = None 211 | # for k in projections.keys(): 212 | # if k[0] != "_": 213 | # key = k 214 | # break 215 | # 216 | # projections = np.array(projections[key]) 217 | # except: ## -- figure out where error is thrown 218 | # #check if the projections are in individual files 219 | # flag = True 220 | # filename_base, file_extension = os.path.splitext(filename) 221 | # projectionCount = 1 222 | # while flag: #first count the number of projections so the array can be initialized 223 | # projectionCount = projectionCount 224 | # nextFile = filename_base + str(projectionCount) + file_extension 225 | # if os.path.isfile(nextFile): 226 | # projectionCount += 1 227 | # else: 228 | # flag = False 229 | # 230 | # 231 | # ## open first projection to get dimensions 232 | # pj = scipy.io.loadmat(filename_base + str(1) + file_extension) 233 | # pj = pj[projections.keys()[0]] 234 | # dims = np.shape(pj) 235 | # #initialize projection array 236 | # projections = np.zeros((dims[0], dims[1], projectionCount),dtype=int) 237 | # 238 | # #now actually load in the tiff images 239 | # for projNum in range(projectionCount): 240 | # nextFile = filename_base + str(projNum) + file_extension 241 | # pj = scipy.io.loadmat(filename_base + str(projNum) + file_extension) 242 | # pj = pj[pj.keys()[0]] 243 | # projections[:, :, projNum] = np.array(pj) 244 | # 245 | # return projections 246 | 247 | 248 | def readTIFF_projections(filename): 249 | """ 250 | * readTIFF * 251 | 252 | Read (possibly multiple) TIFF images into a NumPy array 253 | 254 | :param filename: Name of TIFF file or TIFF file basename to read. If the filename is a base then 255 | # the images must begin with the string contained in filename followed by consecutive integers with 256 | # no zero padding, i.e. foo1.tiff, foo2.tiff,..., foo275.tiff 257 | :return: NumPy array containing projections 258 | 259 | Author: Alan (AJ) Pryor, Jr. 260 | Jianwei (John) Miao Coherent Imaging Group 261 | University of California, Los Angeles 262 | Copyright 2015-2016. All rights reserved. 263 | """ 264 | import functools 265 | from PIL import Image 266 | import os 267 | import numpy as np 268 | from multiprocessing import Pool 269 | try: 270 | projections = np.array(Image.open(filename)) 271 | except: 272 | flag = True 273 | filename_base, file_extension = os.path.splitext(filename) 274 | projectionCount = 1 275 | while flag: #first count the number of projections so the array can be initialized 276 | projectionCount = projectionCount 277 | nextFile = filename_base + str(projectionCount) + file_extension 278 | if os.path.isfile(nextFile): 279 | projectionCount += 1 280 | else: 281 | flag = False 282 | 283 | ## open first projection to get dimensions 284 | dims = np.shape(Image.open(filename_base + str(1) + file_extension)) 285 | 286 | #initialize projection array 287 | projections = np.zeros((dims[0], dims[1], projectionCount),dtype=int) 288 | 289 | pool = Pool(4) 290 | func = functools.partial(readInTiffProjection, filename_base) 291 | pj = pool.map(func, range(projectionCount)) 292 | for j in range(projectionCount): 293 | projections[:, :, j] = pj[j] 294 | return projections 295 | 296 | def readInTiffProjection(filename_base, fileNumber): 297 | """ 298 | * readInTiffProjection * 299 | 300 | Reads and returns a single TIFF image as a NumPy array 301 | 302 | :param filename_base: Base filename of TIFF 303 | :param fileNumber: Image number 304 | :return: Image in a 2D NumPy array 305 | 306 | Author: Alan (AJ) Pryor, Jr. 307 | Jianwei (John) Miao Coherent Imaging Group 308 | University of California, Los Angeles 309 | Copyright 2015-2016. All rights reserved. 310 | """ 311 | from PIL import Image 312 | import numpy as np 313 | nextFile = filename_base + str(fileNumber) + '.tif' 314 | return np.array(Image.open(nextFile)) 315 | 316 | def loadAngles(filename): 317 | """ 318 | * loadAngles * 319 | 320 | Author: Alan (AJ) Pryor, Jr. 321 | Jianwei (John) Miao Coherent Imaging Group 322 | University of California, Los Angeles 323 | Copyright 2015-2016. All rights reserved. 324 | 325 | :param filename: 326 | :return: 327 | """ 328 | import os 329 | base,ext = os.path.splitext(filename) 330 | ext = ext.lower() 331 | if ext == ".txt": 332 | return np.loadtxt(filename,dtype=float) 333 | elif ext== ".npy": 334 | return np.load(filename) 335 | elif ext==".mat": 336 | from genfire.fileio import readVolume 337 | return readVolume(filename) 338 | else: 339 | raise IOError("Unsupported file extension \"{}\" for Euler angles".format(ext)) 340 | 341 | 342 | def saveResults(reconstruction_outputs, filename): 343 | """ 344 | * saveResults * 345 | 346 | Helper function to save results of GENFIRE reconstruction 347 | 348 | :param reconstruction_outputs: dictionary containing reconstruction, reciprocal error (errK), and possible R_free 349 | :param filename: Output filename 350 | 351 | Author: Alan (AJ) Pryor, Jr. 352 | Jianwei (John) Miao Coherent Imaging Group 353 | University of California, Los Angeles 354 | Copyright 2015-2016. All rights reserved 355 | """ 356 | import os 357 | fn, ext = os.path.splitext(filename) 358 | writeVolume(filename, reconstruction_outputs['reconstruction']) 359 | np.savetxt(fn+'_errK.txt',reconstruction_outputs['errK']) 360 | if 'R_free_total' in reconstruction_outputs.keys(): 361 | np.savetxt(fn+'_Rfree_total.txt',reconstruction_outputs['R_free_total']) 362 | np.savetxt(fn+'_Rfree_bybin.txt',reconstruction_outputs['R_free_bybin']) 363 | 364 | def writeVolume(filename, data, order="C"): 365 | """ 366 | * writeVolume * 367 | 368 | Wrapper volume to file 369 | 370 | :param filename: output filename with valid extension 371 | :param data: numpy volume to write 372 | :param order: "C" for row-major order (C-style), "F" for column-major (Fortran style) 373 | """ 374 | import os 375 | fn, ext = os.path.splitext(filename) 376 | if ext == ".mrc": 377 | writeMRC(filename, arr=data, order=order) 378 | elif ext == ".npy": 379 | import numpy as np 380 | np.save(filename,data) 381 | elif ext == ".mat": 382 | import scipy.io 383 | scipy.io.savemat(filename, {"data":data}) 384 | else: 385 | raise IOError("Unsupported file extension \"{}\" for volume object".format(ext)) 386 | -------------------------------------------------------------------------------- /genfire/gui/CalculateProjectionSeries_Dialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'calculateprojectionseries_dialog.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.8.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_CalculateProjectionSeries_Dialog(object): 12 | def setupUi(self, CalculateProjectionSeries_Dialog): 13 | CalculateProjectionSeries_Dialog.setObjectName("CalculateProjectionSeries_Dialog") 14 | CalculateProjectionSeries_Dialog.resize(762, 382) 15 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 16 | sizePolicy.setHorizontalStretch(0) 17 | sizePolicy.setVerticalStretch(0) 18 | sizePolicy.setHeightForWidth(CalculateProjectionSeries_Dialog.sizePolicy().hasHeightForWidth()) 19 | CalculateProjectionSeries_Dialog.setSizePolicy(sizePolicy) 20 | self.horizontalLayout_9 = QtWidgets.QHBoxLayout(CalculateProjectionSeries_Dialog) 21 | self.horizontalLayout_9.setObjectName("horizontalLayout_9") 22 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 23 | self.verticalLayout_2.setObjectName("verticalLayout_2") 24 | self.verticalLayout_8 = QtWidgets.QVBoxLayout() 25 | self.verticalLayout_8.setObjectName("verticalLayout_8") 26 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 27 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 28 | self.label_3 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 29 | self.label_3.setWordWrap(True) 30 | self.label_3.setObjectName("label_3") 31 | self.horizontalLayout_2.addWidget(self.label_3) 32 | self.lineEdit_angleFile = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 33 | self.lineEdit_angleFile.setMinimumSize(QtCore.QSize(500, 0)) 34 | self.lineEdit_angleFile.setObjectName("lineEdit_angleFile") 35 | self.horizontalLayout_2.addWidget(self.lineEdit_angleFile) 36 | self.btn_selectAngleFile = QtWidgets.QPushButton(CalculateProjectionSeries_Dialog) 37 | self.btn_selectAngleFile.setObjectName("btn_selectAngleFile") 38 | self.horizontalLayout_2.addWidget(self.btn_selectAngleFile) 39 | self.verticalLayout_8.addLayout(self.horizontalLayout_2) 40 | self.line = QtWidgets.QFrame(CalculateProjectionSeries_Dialog) 41 | self.line.setFrameShape(QtWidgets.QFrame.HLine) 42 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken) 43 | self.line.setObjectName("line") 44 | self.verticalLayout_8.addWidget(self.line) 45 | self.label_9 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 46 | self.label_9.setObjectName("label_9") 47 | self.verticalLayout_8.addWidget(self.label_9) 48 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout() 49 | self.horizontalLayout_4.setObjectName("horizontalLayout_4") 50 | self.verticalLayout_5 = QtWidgets.QVBoxLayout() 51 | self.verticalLayout_5.setObjectName("verticalLayout_5") 52 | self.label_7 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 53 | self.label_7.setObjectName("label_7") 54 | self.verticalLayout_5.addWidget(self.label_7) 55 | self.label_2 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 56 | self.label_2.setObjectName("label_2") 57 | self.verticalLayout_5.addWidget(self.label_2) 58 | self.label_8 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 59 | self.label_8.setObjectName("label_8") 60 | self.verticalLayout_5.addWidget(self.label_8) 61 | self.horizontalLayout_4.addLayout(self.verticalLayout_5) 62 | self.horizontalLayout = QtWidgets.QHBoxLayout() 63 | self.horizontalLayout.setObjectName("horizontalLayout") 64 | self.horizontalLayout_8 = QtWidgets.QHBoxLayout() 65 | self.horizontalLayout_8.setObjectName("horizontalLayout_8") 66 | self.verticalLayout_6 = QtWidgets.QVBoxLayout() 67 | self.verticalLayout_6.setObjectName("verticalLayout_6") 68 | self.lineEdit_phi = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 69 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 70 | sizePolicy.setHorizontalStretch(0) 71 | sizePolicy.setVerticalStretch(0) 72 | sizePolicy.setHeightForWidth(self.lineEdit_phi.sizePolicy().hasHeightForWidth()) 73 | self.lineEdit_phi.setSizePolicy(sizePolicy) 74 | self.lineEdit_phi.setMaxLength(6) 75 | self.lineEdit_phi.setAlignment(QtCore.Qt.AlignCenter) 76 | self.lineEdit_phi.setObjectName("lineEdit_phi") 77 | self.verticalLayout_6.addWidget(self.lineEdit_phi) 78 | self.verticalLayout = QtWidgets.QVBoxLayout() 79 | self.verticalLayout.setObjectName("verticalLayout") 80 | self.lineEdit_thetaStart = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 81 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 82 | sizePolicy.setHorizontalStretch(0) 83 | sizePolicy.setVerticalStretch(0) 84 | sizePolicy.setHeightForWidth(self.lineEdit_thetaStart.sizePolicy().hasHeightForWidth()) 85 | self.lineEdit_thetaStart.setSizePolicy(sizePolicy) 86 | self.lineEdit_thetaStart.setMaxLength(6) 87 | self.lineEdit_thetaStart.setAlignment(QtCore.Qt.AlignCenter) 88 | self.lineEdit_thetaStart.setObjectName("lineEdit_thetaStart") 89 | self.verticalLayout.addWidget(self.lineEdit_thetaStart) 90 | self.verticalLayout_6.addLayout(self.verticalLayout) 91 | self.lineEdit_psi = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 92 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 93 | sizePolicy.setHorizontalStretch(0) 94 | sizePolicy.setVerticalStretch(0) 95 | sizePolicy.setHeightForWidth(self.lineEdit_psi.sizePolicy().hasHeightForWidth()) 96 | self.lineEdit_psi.setSizePolicy(sizePolicy) 97 | self.lineEdit_psi.setMinimumSize(QtCore.QSize(10, 20)) 98 | self.lineEdit_psi.setBaseSize(QtCore.QSize(2, 0)) 99 | self.lineEdit_psi.setMaxLength(6) 100 | self.lineEdit_psi.setAlignment(QtCore.Qt.AlignCenter) 101 | self.lineEdit_psi.setObjectName("lineEdit_psi") 102 | self.verticalLayout_6.addWidget(self.lineEdit_psi) 103 | self.horizontalLayout_8.addLayout(self.verticalLayout_6) 104 | self.label_4 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 105 | self.label_4.setObjectName("label_4") 106 | self.horizontalLayout_8.addWidget(self.label_4) 107 | self.horizontalLayout.addLayout(self.horizontalLayout_8) 108 | self.verticalLayout_9 = QtWidgets.QVBoxLayout() 109 | self.verticalLayout_9.setObjectName("verticalLayout_9") 110 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 111 | self.verticalLayout_9.addItem(spacerItem) 112 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout() 113 | self.horizontalLayout_5.setObjectName("horizontalLayout_5") 114 | self.lineEdit_thetaStep = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 115 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 116 | sizePolicy.setHorizontalStretch(0) 117 | sizePolicy.setVerticalStretch(0) 118 | sizePolicy.setHeightForWidth(self.lineEdit_thetaStep.sizePolicy().hasHeightForWidth()) 119 | self.lineEdit_thetaStep.setSizePolicy(sizePolicy) 120 | self.lineEdit_thetaStep.setMaxLength(6) 121 | self.lineEdit_thetaStep.setAlignment(QtCore.Qt.AlignCenter) 122 | self.lineEdit_thetaStep.setObjectName("lineEdit_thetaStep") 123 | self.horizontalLayout_5.addWidget(self.lineEdit_thetaStep) 124 | self.label_5 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 125 | self.label_5.setObjectName("label_5") 126 | self.horizontalLayout_5.addWidget(self.label_5) 127 | self.verticalLayout_9.addLayout(self.horizontalLayout_5) 128 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 129 | self.verticalLayout_9.addItem(spacerItem1) 130 | self.horizontalLayout.addLayout(self.verticalLayout_9) 131 | self.verticalLayout_10 = QtWidgets.QVBoxLayout() 132 | self.verticalLayout_10.setObjectName("verticalLayout_10") 133 | spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 134 | self.verticalLayout_10.addItem(spacerItem2) 135 | self.horizontalLayout_7 = QtWidgets.QHBoxLayout() 136 | self.horizontalLayout_7.setObjectName("horizontalLayout_7") 137 | self.lineEdit_thetaStop = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 138 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 139 | sizePolicy.setHorizontalStretch(0) 140 | sizePolicy.setVerticalStretch(0) 141 | sizePolicy.setHeightForWidth(self.lineEdit_thetaStop.sizePolicy().hasHeightForWidth()) 142 | self.lineEdit_thetaStop.setSizePolicy(sizePolicy) 143 | self.lineEdit_thetaStop.setMaxLength(6) 144 | self.lineEdit_thetaStop.setAlignment(QtCore.Qt.AlignCenter) 145 | self.lineEdit_thetaStop.setObjectName("lineEdit_thetaStop") 146 | self.horizontalLayout_7.addWidget(self.lineEdit_thetaStop) 147 | self.label_6 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 148 | self.label_6.setObjectName("label_6") 149 | self.horizontalLayout_7.addWidget(self.label_6) 150 | self.verticalLayout_10.addLayout(self.horizontalLayout_7) 151 | spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 152 | self.verticalLayout_10.addItem(spacerItem3) 153 | self.horizontalLayout.addLayout(self.verticalLayout_10) 154 | self.horizontalLayout_4.addLayout(self.horizontalLayout) 155 | self.verticalLayout_8.addLayout(self.horizontalLayout_4) 156 | self.horizontalLayout_11 = QtWidgets.QHBoxLayout() 157 | self.horizontalLayout_11.setObjectName("horizontalLayout_11") 158 | self.checkBox_saveAngles = QtWidgets.QCheckBox(CalculateProjectionSeries_Dialog) 159 | self.checkBox_saveAngles.setObjectName("checkBox_saveAngles") 160 | self.horizontalLayout_11.addWidget(self.checkBox_saveAngles) 161 | spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 162 | self.horizontalLayout_11.addItem(spacerItem4) 163 | self.verticalLayout_8.addLayout(self.horizontalLayout_11) 164 | self.horizontalLayout_6 = QtWidgets.QHBoxLayout() 165 | self.horizontalLayout_6.setObjectName("horizontalLayout_6") 166 | self.label = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 167 | self.label.setWordWrap(True) 168 | self.label.setObjectName("label") 169 | self.horizontalLayout_6.addWidget(self.label) 170 | self.lineEdit_outputFilename = QtWidgets.QLineEdit(CalculateProjectionSeries_Dialog) 171 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 172 | sizePolicy.setHorizontalStretch(0) 173 | sizePolicy.setVerticalStretch(0) 174 | sizePolicy.setHeightForWidth(self.lineEdit_outputFilename.sizePolicy().hasHeightForWidth()) 175 | self.lineEdit_outputFilename.setSizePolicy(sizePolicy) 176 | self.lineEdit_outputFilename.setObjectName("lineEdit_outputFilename") 177 | self.horizontalLayout_6.addWidget(self.lineEdit_outputFilename) 178 | self.verticalLayout_8.addLayout(self.horizontalLayout_6) 179 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 180 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 181 | self.verticalLayout_8.addLayout(self.horizontalLayout_3) 182 | self.label_10 = QtWidgets.QLabel(CalculateProjectionSeries_Dialog) 183 | self.label_10.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) 184 | self.label_10.setObjectName("label_10") 185 | self.verticalLayout_8.addWidget(self.label_10) 186 | self.line_2 = QtWidgets.QFrame(CalculateProjectionSeries_Dialog) 187 | self.line_2.setFrameShape(QtWidgets.QFrame.HLine) 188 | self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) 189 | self.line_2.setObjectName("line_2") 190 | self.verticalLayout_8.addWidget(self.line_2) 191 | self.buttonBox = QtWidgets.QDialogButtonBox(CalculateProjectionSeries_Dialog) 192 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 193 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) 194 | self.buttonBox.setObjectName("buttonBox") 195 | self.verticalLayout_8.addWidget(self.buttonBox) 196 | self.verticalLayout_2.addLayout(self.verticalLayout_8) 197 | self.horizontalLayout_9.addLayout(self.verticalLayout_2) 198 | 199 | self.retranslateUi(CalculateProjectionSeries_Dialog) 200 | self.buttonBox.accepted.connect(CalculateProjectionSeries_Dialog.accept) 201 | self.buttonBox.rejected.connect(CalculateProjectionSeries_Dialog.reject) 202 | QtCore.QMetaObject.connectSlotsByName(CalculateProjectionSeries_Dialog) 203 | CalculateProjectionSeries_Dialog.setTabOrder(self.lineEdit_angleFile, self.btn_selectAngleFile) 204 | CalculateProjectionSeries_Dialog.setTabOrder(self.btn_selectAngleFile, self.lineEdit_phi) 205 | CalculateProjectionSeries_Dialog.setTabOrder(self.lineEdit_phi, self.lineEdit_thetaStart) 206 | CalculateProjectionSeries_Dialog.setTabOrder(self.lineEdit_thetaStart, self.lineEdit_psi) 207 | CalculateProjectionSeries_Dialog.setTabOrder(self.lineEdit_psi, self.lineEdit_outputFilename) 208 | 209 | def retranslateUi(self, CalculateProjectionSeries_Dialog): 210 | _translate = QtCore.QCoreApplication.translate 211 | CalculateProjectionSeries_Dialog.setWindowTitle(_translate("CalculateProjectionSeries_Dialog", "Dialog")) 212 | self.label_3.setText(_translate("CalculateProjectionSeries_Dialog", "Filename Containing Euler Angles")) 213 | self.btn_selectAngleFile.setText(_translate("CalculateProjectionSeries_Dialog", "Browse")) 214 | self.label_9.setText(_translate("CalculateProjectionSeries_Dialog", "Generate Euler Angles")) 215 | self.label_7.setText(_translate("CalculateProjectionSeries_Dialog", "Phi")) 216 | self.label_2.setText(_translate("CalculateProjectionSeries_Dialog", "Theta (Tilt)")) 217 | self.label_8.setText(_translate("CalculateProjectionSeries_Dialog", "Psi")) 218 | self.label_4.setText(_translate("CalculateProjectionSeries_Dialog", "Start")) 219 | self.label_5.setText(_translate("CalculateProjectionSeries_Dialog", "Step")) 220 | self.label_6.setText(_translate("CalculateProjectionSeries_Dialog", "Stop")) 221 | self.checkBox_saveAngles.setText(_translate("CalculateProjectionSeries_Dialog", "Save Angles")) 222 | self.label.setText(_translate("CalculateProjectionSeries_Dialog", "Projection Filename")) 223 | self.label_10.setText(_translate("CalculateProjectionSeries_Dialog", "*.mrc, *.npy, or *.mat")) 224 | 225 | -------------------------------------------------------------------------------- /genfire/gui/GENFIRE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/genfire/gui/GENFIRE.png -------------------------------------------------------------------------------- /genfire/gui/GENFIRE.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2016-02-09T15:04:18 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 5): QT += widgets 10 | 11 | TARGET = GENFIRE 12 | 13 | TEMPLATE = app 14 | 15 | 16 | SOURCES += GENFIRE_MainWindow.cpp 17 | 18 | HEADERS += GENFIRE_MainWindow.h 19 | 20 | FORMS += GENFIRE_MainWindow.ui \ 21 | ProjectionCalculator_MainWindow.ui \ 22 | VolumeSlicer_MainWindow.ui \ 23 | CalculateProjectionSeries_Dialog.ui \ 24 | calculateprojectionseries_dialog.ui 25 | 26 | RESOURCES += GENFIRE.qrc 27 | -------------------------------------------------------------------------------- /genfire/gui/GENFIRE.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | GENFIRE.png 4 | GF.png 5 | 6 | 7 | -------------------------------------------------------------------------------- /genfire/gui/GENFIRE_MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "GENFIRE_MainWindow.h" 2 | #include "ui_GENFIRE_MainWindow.h" 3 | 4 | GENFIRE_MainWindow::GENFIRE_MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::GENFIRE_MainWindow) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | GENFIRE_MainWindow::~GENFIRE_MainWindow() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /genfire/gui/GENFIRE_MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef GENFIRE_MainWindow_H 2 | #define GENFIRE_MainWindow_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class GENFIRE_MainWindow; 8 | } 9 | 10 | class GENFIRE_MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit GENFIRE_MainWindow(QWidget *parent = 0); 16 | ~GENFIRE_MainWindow(); 17 | 18 | private: 19 | Ui::GENFIRE_MainWindow *ui; 20 | }; 21 | 22 | #endif // GENFIRE_MainWindow_H 23 | -------------------------------------------------------------------------------- /genfire/gui/GF.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/genfire/gui/GF.icns -------------------------------------------------------------------------------- /genfire/gui/GF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genfire-em/GENFIRE-Python/b7b46daed4adf4f3afccea95ca71fa88e7c39e0a/genfire/gui/GF.png -------------------------------------------------------------------------------- /genfire/gui/ProjectionCalculator_MainWindow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ProjectionCalculator_MainWindow.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.8.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_ProjectionCalculator(object): 12 | def setupUi(self, ProjectionCalculator): 13 | ProjectionCalculator.setObjectName("ProjectionCalculator") 14 | ProjectionCalculator.resize(819, 1000) 15 | self.centralwidget = QtWidgets.QWidget(ProjectionCalculator) 16 | self.centralwidget.setObjectName("centralwidget") 17 | self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget) 18 | self.gridLayout_3.setObjectName("gridLayout_3") 19 | self.gridLayout_2 = QtWidgets.QGridLayout() 20 | self.gridLayout_2.setObjectName("gridLayout_2") 21 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout() 22 | self.horizontalLayout_4.setObjectName("horizontalLayout_4") 23 | self.btn_clearModel = QtWidgets.QPushButton(self.centralwidget) 24 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.btn_clearModel.sizePolicy().hasHeightForWidth()) 28 | self.btn_clearModel.setSizePolicy(sizePolicy) 29 | self.btn_clearModel.setObjectName("btn_clearModel") 30 | self.horizontalLayout_4.addWidget(self.btn_clearModel) 31 | self.btn_go = QtWidgets.QPushButton(self.centralwidget) 32 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) 33 | sizePolicy.setHorizontalStretch(0) 34 | sizePolicy.setVerticalStretch(0) 35 | sizePolicy.setHeightForWidth(self.btn_go.sizePolicy().hasHeightForWidth()) 36 | self.btn_go.setSizePolicy(sizePolicy) 37 | palette = QtGui.QPalette() 38 | brush = QtGui.QBrush(QtGui.QColor(179, 179, 179)) 39 | brush.setStyle(QtCore.Qt.SolidPattern) 40 | palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush) 41 | brush = QtGui.QBrush(QtGui.QColor(179, 179, 179)) 42 | brush.setStyle(QtCore.Qt.SolidPattern) 43 | palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush) 44 | brush = QtGui.QBrush(QtGui.QColor(179, 179, 179)) 45 | brush.setStyle(QtCore.Qt.SolidPattern) 46 | palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush) 47 | self.btn_go.setPalette(palette) 48 | self.btn_go.setObjectName("btn_go") 49 | self.horizontalLayout_4.addWidget(self.btn_go) 50 | self.gridLayout_2.addLayout(self.horizontalLayout_4, 2, 0, 1, 4) 51 | self.gridLayout = QtWidgets.QGridLayout() 52 | self.gridLayout.setObjectName("gridLayout") 53 | self.horizontalLayout_6 = QtWidgets.QHBoxLayout() 54 | self.horizontalLayout_6.setObjectName("horizontalLayout_6") 55 | self.verticalSlider_theta = QtWidgets.QSlider(self.centralwidget) 56 | self.verticalSlider_theta.setMaximum(3600) 57 | self.verticalSlider_theta.setSingleStep(10) 58 | self.verticalSlider_theta.setPageStep(100) 59 | self.verticalSlider_theta.setOrientation(QtCore.Qt.Vertical) 60 | self.verticalSlider_theta.setObjectName("verticalSlider_theta") 61 | self.horizontalLayout_6.addWidget(self.verticalSlider_theta) 62 | self.gridLayout.addLayout(self.horizontalLayout_6, 0, 1, 1, 1) 63 | self.label_6 = QtWidgets.QLabel(self.centralwidget) 64 | self.label_6.setAlignment(QtCore.Qt.AlignCenter) 65 | self.label_6.setObjectName("label_6") 66 | self.gridLayout.addWidget(self.label_6, 2, 0, 1, 1) 67 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout() 68 | self.horizontalLayout_5.setObjectName("horizontalLayout_5") 69 | self.verticalSlider_phi = QtWidgets.QSlider(self.centralwidget) 70 | self.verticalSlider_phi.setLayoutDirection(QtCore.Qt.LeftToRight) 71 | self.verticalSlider_phi.setMaximum(3600) 72 | self.verticalSlider_phi.setSingleStep(1) 73 | self.verticalSlider_phi.setPageStep(100) 74 | self.verticalSlider_phi.setOrientation(QtCore.Qt.Vertical) 75 | self.verticalSlider_phi.setTickPosition(QtWidgets.QSlider.NoTicks) 76 | self.verticalSlider_phi.setTickInterval(1) 77 | self.verticalSlider_phi.setObjectName("verticalSlider_phi") 78 | self.horizontalLayout_5.addWidget(self.verticalSlider_phi) 79 | self.gridLayout.addLayout(self.horizontalLayout_5, 0, 0, 1, 1) 80 | self.horizontalLayout_7 = QtWidgets.QHBoxLayout() 81 | self.horizontalLayout_7.setObjectName("horizontalLayout_7") 82 | self.verticalSlider_psi = QtWidgets.QSlider(self.centralwidget) 83 | self.verticalSlider_psi.setMaximum(360) 84 | self.verticalSlider_psi.setSingleStep(10) 85 | self.verticalSlider_psi.setPageStep(100) 86 | self.verticalSlider_psi.setOrientation(QtCore.Qt.Vertical) 87 | self.verticalSlider_psi.setObjectName("verticalSlider_psi") 88 | self.horizontalLayout_7.addWidget(self.verticalSlider_psi) 89 | self.gridLayout.addLayout(self.horizontalLayout_7, 0, 2, 1, 1) 90 | self.lineEdit_psi = QtWidgets.QLineEdit(self.centralwidget) 91 | self.lineEdit_psi.setAlignment(QtCore.Qt.AlignCenter) 92 | self.lineEdit_psi.setObjectName("lineEdit_psi") 93 | self.gridLayout.addWidget(self.lineEdit_psi, 1, 2, 1, 1) 94 | self.label_8 = QtWidgets.QLabel(self.centralwidget) 95 | self.label_8.setAlignment(QtCore.Qt.AlignCenter) 96 | self.label_8.setObjectName("label_8") 97 | self.gridLayout.addWidget(self.label_8, 2, 2, 1, 1) 98 | self.lineEdit_theta = QtWidgets.QLineEdit(self.centralwidget) 99 | self.lineEdit_theta.setAlignment(QtCore.Qt.AlignCenter) 100 | self.lineEdit_theta.setObjectName("lineEdit_theta") 101 | self.gridLayout.addWidget(self.lineEdit_theta, 1, 1, 1, 1) 102 | self.label_7 = QtWidgets.QLabel(self.centralwidget) 103 | self.label_7.setAlignment(QtCore.Qt.AlignCenter) 104 | self.label_7.setObjectName("label_7") 105 | self.gridLayout.addWidget(self.label_7, 2, 1, 1, 1) 106 | self.lineEdit_phi = QtWidgets.QLineEdit(self.centralwidget) 107 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 108 | sizePolicy.setHorizontalStretch(0) 109 | sizePolicy.setVerticalStretch(0) 110 | sizePolicy.setHeightForWidth(self.lineEdit_phi.sizePolicy().hasHeightForWidth()) 111 | self.lineEdit_phi.setSizePolicy(sizePolicy) 112 | self.lineEdit_phi.setAlignment(QtCore.Qt.AlignCenter) 113 | self.lineEdit_phi.setObjectName("lineEdit_phi") 114 | self.gridLayout.addWidget(self.lineEdit_phi, 1, 0, 1, 1) 115 | self.gridLayout_2.addLayout(self.gridLayout, 0, 3, 1, 1) 116 | self.verticalLayout_figure = QtWidgets.QVBoxLayout() 117 | self.verticalLayout_figure.setObjectName("verticalLayout_figure") 118 | self.horizontalLayout_9 = QtWidgets.QHBoxLayout() 119 | self.horizontalLayout_9.setObjectName("horizontalLayout_9") 120 | self.verticalLayout_figure.addLayout(self.horizontalLayout_9) 121 | self.gridLayout_2.addLayout(self.verticalLayout_figure, 0, 1, 1, 2) 122 | self.horizontalLayout = QtWidgets.QHBoxLayout() 123 | self.horizontalLayout.setObjectName("horizontalLayout") 124 | self.label_2 = QtWidgets.QLabel(self.centralwidget) 125 | self.label_2.setObjectName("label_2") 126 | self.horizontalLayout.addWidget(self.label_2) 127 | self.lineEdit_modelFile = QtWidgets.QLineEdit(self.centralwidget) 128 | self.lineEdit_modelFile.setObjectName("lineEdit_modelFile") 129 | self.horizontalLayout.addWidget(self.lineEdit_modelFile) 130 | self.btn_selectModel = QtWidgets.QPushButton(self.centralwidget) 131 | self.btn_selectModel.setObjectName("btn_selectModel") 132 | self.horizontalLayout.addWidget(self.btn_selectModel) 133 | self.gridLayout_2.addLayout(self.horizontalLayout, 1, 0, 1, 4) 134 | self.gridLayout_3.addLayout(self.gridLayout_2, 0, 0, 1, 1) 135 | ProjectionCalculator.setCentralWidget(self.centralwidget) 136 | self.menubar = QtWidgets.QMenuBar(ProjectionCalculator) 137 | self.menubar.setGeometry(QtCore.QRect(0, 0, 819, 22)) 138 | self.menubar.setObjectName("menubar") 139 | ProjectionCalculator.setMenuBar(self.menubar) 140 | self.statusbar = QtWidgets.QStatusBar(ProjectionCalculator) 141 | self.statusbar.setObjectName("statusbar") 142 | ProjectionCalculator.setStatusBar(self.statusbar) 143 | 144 | self.retranslateUi(ProjectionCalculator) 145 | QtCore.QMetaObject.connectSlotsByName(ProjectionCalculator) 146 | ProjectionCalculator.setTabOrder(self.lineEdit_phi, self.lineEdit_theta) 147 | ProjectionCalculator.setTabOrder(self.lineEdit_theta, self.lineEdit_psi) 148 | ProjectionCalculator.setTabOrder(self.lineEdit_psi, self.lineEdit_modelFile) 149 | ProjectionCalculator.setTabOrder(self.lineEdit_modelFile, self.btn_selectModel) 150 | 151 | def retranslateUi(self, ProjectionCalculator): 152 | _translate = QtCore.QCoreApplication.translate 153 | ProjectionCalculator.setWindowTitle(_translate("ProjectionCalculator", "Projection Calculator")) 154 | self.btn_clearModel.setText(_translate("ProjectionCalculator", "Clear Model")) 155 | self.btn_go.setText(_translate("ProjectionCalculator", "Calculate Projection Series From Model")) 156 | self.label_6.setText(_translate("ProjectionCalculator", "Phi")) 157 | self.label_8.setText(_translate("ProjectionCalculator", "Psi")) 158 | self.label_7.setText(_translate("ProjectionCalculator", "Theta")) 159 | self.label_2.setText(_translate("ProjectionCalculator", "Model")) 160 | self.btn_selectModel.setText(_translate("ProjectionCalculator", "Browse")) 161 | 162 | -------------------------------------------------------------------------------- /genfire/gui/ProjectionCalculator_MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ProjectionCalculator 4 | 5 | 6 | 7 | 0 8 | 0 9 | 819 10 | 1000 11 | 12 | 13 | 14 | Projection Calculator 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 29 | 30 | 31 | Clear Model 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 0 40 | 0 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 179 50 | 179 51 | 179 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 179 61 | 179 62 | 179 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 179 72 | 179 73 | 179 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Calculate Projection Series From Model 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 3600 95 | 96 | 97 | 10 98 | 99 | 100 | 100 101 | 102 | 103 | Qt::Vertical 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Phi 113 | 114 | 115 | Qt::AlignCenter 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Qt::LeftToRight 125 | 126 | 127 | 3600 128 | 129 | 130 | 1 131 | 132 | 133 | 100 134 | 135 | 136 | Qt::Vertical 137 | 138 | 139 | QSlider::NoTicks 140 | 141 | 142 | 1 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 360 154 | 155 | 156 | 10 157 | 158 | 159 | 100 160 | 161 | 162 | Qt::Vertical 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | Qt::AlignCenter 172 | 173 | 174 | 175 | 176 | 177 | 178 | Psi 179 | 180 | 181 | Qt::AlignCenter 182 | 183 | 184 | 185 | 186 | 187 | 188 | Qt::AlignCenter 189 | 190 | 191 | 192 | 193 | 194 | 195 | Theta 196 | 197 | 198 | Qt::AlignCenter 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 0 207 | 0 208 | 209 | 210 | 211 | Qt::AlignCenter 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | Model 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | Browse 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 0 253 | 0 254 | 819 255 | 22 256 | 257 | 258 | 259 | 260 | 261 | 262 | lineEdit_phi 263 | lineEdit_theta 264 | lineEdit_psi 265 | lineEdit_modelFile 266 | btn_selectModel 267 | 268 | 269 | 270 | 271 | -------------------------------------------------------------------------------- /genfire/gui/VolumeSlicer.py: -------------------------------------------------------------------------------- 1 | """ 2 | * genfire.gui.VolumeSlicer * 3 | 4 | The volume slicer module 5 | 6 | 7 | Author: Alan (AJ) Pryor, Jr. 8 | Jianwei (John) Miao Coherent Imaging Group 9 | University of California, Los Angeles 10 | Copyright 2015-2016. All rights reserved. 11 | """ 12 | 13 | from genfire.gui import VolumeSlicer_MainWindow 14 | from PyQt5 import QtCore, QtGui, QtWidgets 15 | import matplotlib 16 | matplotlib.use("Qt5Agg") 17 | import matplotlib.pyplot as plt 18 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 19 | from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar 20 | import numpy as np 21 | from functools import partial 22 | from genfire.gui.utility import toString, toQString, toInt, toFloat 23 | 24 | 25 | class VolumeSlicer(QtWidgets.QMainWindow): 26 | def __init__(self, volume): 27 | super(VolumeSlicer, self).__init__() 28 | self.volume = volume 29 | self.ui = VolumeSlicer_MainWindow.Ui_VolumeSlicer() 30 | self.ui.setupUi(self) # build interface 31 | 32 | self.ui.checkBox_lockcmap.toggled.connect(self.toggleLockCmap) 33 | self.lockColormap = False 34 | self.ui.checkBox_lockcmap.setChecked(False) 35 | 36 | # figures for plotting 37 | self.fig1 = plt.figure() 38 | self.fig2 = plt.figure() 39 | self.fig3 = plt.figure() 40 | 41 | # canvases link the Qt widgets with the matplotlib figures 42 | self.canvas1 = FigureCanvas(self.fig1) 43 | self.canvas2 = FigureCanvas(self.fig2) 44 | self.canvas3 = FigureCanvas(self.fig3) 45 | 46 | self.slice1 = self.fig1.add_subplot(111) 47 | self.slice2 = self.fig2.add_subplot(111) 48 | self.slice3 = self.fig3.add_subplot(111) 49 | 50 | self.navigationToolbar1 = NavigationToolbar(self.canvas1, self) 51 | self.navigationToolbar2 = NavigationToolbar(self.canvas2, self) 52 | self.navigationToolbar3 = NavigationToolbar(self.canvas3, self) 53 | 54 | self.ui.vt_lyt_fig1.addWidget(self.navigationToolbar1) 55 | self.ui.vt_lyt_fig1.addWidget(self.canvas1) 56 | self.ui.vt_lyt_fig2.addWidget(self.navigationToolbar2) 57 | self.ui.vt_lyt_fig2.addWidget(self.canvas2) 58 | self.ui.vt_lyt_fig3.addWidget(self.navigationToolbar3) 59 | self.ui.vt_lyt_fig3.addWidget(self.canvas3) 60 | 61 | dimx, dimy, dimz = np.shape(volume) 62 | ncx, ncy, ncz = dimx//2., dimy//2, dimz//2 63 | ncx, ncy, ncz = int(ncx), int(ncy), int(ncz) 64 | 65 | # use of partial allows binding functions to arguments to prevent having to avoid extra parameter forwarding 66 | self.ui.scrlbr_fig1.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr1)) 67 | self.ui.scrlbr_fig2.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr2)) 68 | self.ui.scrlbr_fig3.valueChanged.connect(partial(self.setTextFromSlider,self.ui.lineEdit_scrlbr3)) 69 | 70 | self.ui.scrlbr_fig1.setValue(ncx) 71 | self.ui.scrlbr_fig1.setMinimum(0) 72 | self.ui.scrlbr_fig1.setMaximum(dimx-1) 73 | 74 | self.ui.scrlbr_fig2.setValue(ncy) 75 | self.ui.scrlbr_fig2.setMinimum(0) 76 | self.ui.scrlbr_fig2.setMaximum(dimy-1) 77 | 78 | self.ui.scrlbr_fig3.setValue(ncz) 79 | self.ui.scrlbr_fig3.setMinimum(0) 80 | self.ui.scrlbr_fig3.setMaximum(dimz-1) 81 | 82 | self.ui.lineEdit_scrlbr1.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig1)) 83 | self.ui.lineEdit_scrlbr2.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig2)) 84 | self.ui.lineEdit_scrlbr3.textChanged.connect(partial(self.setSliderFromText,self.ui.scrlbr_fig3)) 85 | 86 | self.currentSliceX = ncx 87 | self.currentSliceY = ncy 88 | self.currentSliceZ = ncz 89 | self.updateAll() 90 | 91 | self.ui.scrlbr_fig1.valueChanged[int].connect(self.updateSliceX) 92 | self.ui.scrlbr_fig2.valueChanged[int].connect(self.updateSliceY) 93 | self.ui.scrlbr_fig3.valueChanged[int].connect(self.updateSliceZ) 94 | 95 | self.clim1 = plt.getp(plt.getp(self.slice1,'images')[0],'clim') 96 | self.clim2 = plt.getp(plt.getp(self.slice2,'images')[0],'clim') 97 | self.clim3 = plt.getp(plt.getp(self.slice3,'images')[0],'clim') 98 | 99 | self.lockColormap = True 100 | self.ui.checkBox_lockcmap.setChecked(True) 101 | 102 | 103 | def updateSliceX(self, nx): 104 | self.slice1.imshow(np.squeeze(self.volume[nx, :, :])) 105 | if self.lockColormap: 106 | plt.setp(plt.getp(self.slice1,'images')[0],'clim',self.clim1) 107 | self.canvas1.draw() 108 | 109 | def updateSliceY(self, ny): 110 | self.slice2.imshow(np.squeeze(self.volume[:, ny, :])) 111 | if self.lockColormap: 112 | plt.setp(plt.getp(self.slice2,'images')[0],'clim',self.clim2) 113 | self.canvas2.draw() 114 | 115 | def updateSliceZ(self, nz): 116 | self.slice3.imshow(np.squeeze(self.volume[:, :, nz])) 117 | if self.lockColormap: 118 | plt.setp(plt.getp(self.slice3,'images')[0],'clim',self.clim3) 119 | self.canvas3.draw() 120 | 121 | def updateAll(self): 122 | self.updateSliceX(self.currentSliceX) 123 | self.updateSliceY(self.currentSliceY) 124 | self.updateSliceZ(self.currentSliceZ) 125 | 126 | def toggleLockCmap(self): 127 | if self.ui.checkBox_lockcmap.isChecked(): 128 | self.clim1 = plt.getp(plt.getp(self.slice1,'images')[0],'clim') 129 | self.clim2 = plt.getp(plt.getp(self.slice2,'images')[0],'clim') 130 | self.clim3 = plt.getp(plt.getp(self.slice3,'images')[0],'clim') 131 | self.lockColormap = True 132 | else: 133 | self.lockColormap = False 134 | 135 | def setSliderFromText(self, slider, text): 136 | try: 137 | val = toInt(text) 138 | except: 139 | val = 1 140 | slider.setValue(val) 141 | 142 | def setTextFromSlider(self, lineedit, value): 143 | lineedit.setText(toQString(value)) 144 | -------------------------------------------------------------------------------- /genfire/gui/VolumeSlicer_MainWindow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'VolumeSlicer_MainWindow.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.8.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_VolumeSlicer(object): 12 | def setupUi(self, VolumeSlicer): 13 | VolumeSlicer.setObjectName("VolumeSlicer") 14 | VolumeSlicer.resize(1800, 800) 15 | self.centralwidget = QtWidgets.QWidget(VolumeSlicer) 16 | self.centralwidget.setObjectName("centralwidget") 17 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget) 18 | self.verticalLayout_2.setObjectName("verticalLayout_2") 19 | self.hz_lyt_figures = QtWidgets.QHBoxLayout() 20 | self.hz_lyt_figures.setObjectName("hz_lyt_figures") 21 | self.vt_lyt_fig1 = QtWidgets.QVBoxLayout() 22 | self.vt_lyt_fig1.setObjectName("vt_lyt_fig1") 23 | self.hz_lyt_figures.addLayout(self.vt_lyt_fig1) 24 | self.vt_lyt_fig2 = QtWidgets.QVBoxLayout() 25 | self.vt_lyt_fig2.setObjectName("vt_lyt_fig2") 26 | self.hz_lyt_figures.addLayout(self.vt_lyt_fig2) 27 | self.vt_lyt_fig3 = QtWidgets.QVBoxLayout() 28 | self.vt_lyt_fig3.setObjectName("vt_lyt_fig3") 29 | self.hz_lyt_figures.addLayout(self.vt_lyt_fig3) 30 | self.verticalLayout_2.addLayout(self.hz_lyt_figures) 31 | self.verticalLayout = QtWidgets.QVBoxLayout() 32 | self.verticalLayout.setObjectName("verticalLayout") 33 | self.hz_lyt_sliders = QtWidgets.QHBoxLayout() 34 | self.hz_lyt_sliders.setObjectName("hz_lyt_sliders") 35 | self.sldr_fig1 = QtWidgets.QVBoxLayout() 36 | self.sldr_fig1.setObjectName("sldr_fig1") 37 | self.scrlbr_fig1 = QtWidgets.QScrollBar(self.centralwidget) 38 | self.scrlbr_fig1.setOrientation(QtCore.Qt.Horizontal) 39 | self.scrlbr_fig1.setInvertedAppearance(False) 40 | self.scrlbr_fig1.setObjectName("scrlbr_fig1") 41 | self.sldr_fig1.addWidget(self.scrlbr_fig1) 42 | self.horizontalLayout = QtWidgets.QHBoxLayout() 43 | self.horizontalLayout.setObjectName("horizontalLayout") 44 | self.horizontalLayout_6 = QtWidgets.QHBoxLayout() 45 | self.horizontalLayout_6.setObjectName("horizontalLayout_6") 46 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 47 | self.horizontalLayout_6.addItem(spacerItem) 48 | self.label = QtWidgets.QLabel(self.centralwidget) 49 | self.label.setObjectName("label") 50 | self.horizontalLayout_6.addWidget(self.label) 51 | self.horizontalLayout.addLayout(self.horizontalLayout_6) 52 | self.lineEdit_scrlbr1 = QtWidgets.QLineEdit(self.centralwidget) 53 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 54 | sizePolicy.setHorizontalStretch(0) 55 | sizePolicy.setVerticalStretch(0) 56 | sizePolicy.setHeightForWidth(self.lineEdit_scrlbr1.sizePolicy().hasHeightForWidth()) 57 | self.lineEdit_scrlbr1.setSizePolicy(sizePolicy) 58 | self.lineEdit_scrlbr1.setAlignment(QtCore.Qt.AlignCenter) 59 | self.lineEdit_scrlbr1.setObjectName("lineEdit_scrlbr1") 60 | self.horizontalLayout.addWidget(self.lineEdit_scrlbr1) 61 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 62 | self.horizontalLayout.addItem(spacerItem1) 63 | self.sldr_fig1.addLayout(self.horizontalLayout) 64 | self.hz_lyt_sliders.addLayout(self.sldr_fig1) 65 | self.sldr_fig2 = QtWidgets.QVBoxLayout() 66 | self.sldr_fig2.setObjectName("sldr_fig2") 67 | self.scrlbr_fig2 = QtWidgets.QScrollBar(self.centralwidget) 68 | self.scrlbr_fig2.setOrientation(QtCore.Qt.Horizontal) 69 | self.scrlbr_fig2.setObjectName("scrlbr_fig2") 70 | self.sldr_fig2.addWidget(self.scrlbr_fig2) 71 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 72 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 73 | self.horizontalLayout_8 = QtWidgets.QHBoxLayout() 74 | self.horizontalLayout_8.setObjectName("horizontalLayout_8") 75 | spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 76 | self.horizontalLayout_8.addItem(spacerItem2) 77 | self.label_2 = QtWidgets.QLabel(self.centralwidget) 78 | self.label_2.setObjectName("label_2") 79 | self.horizontalLayout_8.addWidget(self.label_2) 80 | self.horizontalLayout_2.addLayout(self.horizontalLayout_8) 81 | self.lineEdit_scrlbr2 = QtWidgets.QLineEdit(self.centralwidget) 82 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 83 | sizePolicy.setHorizontalStretch(0) 84 | sizePolicy.setVerticalStretch(0) 85 | sizePolicy.setHeightForWidth(self.lineEdit_scrlbr2.sizePolicy().hasHeightForWidth()) 86 | self.lineEdit_scrlbr2.setSizePolicy(sizePolicy) 87 | self.lineEdit_scrlbr2.setAlignment(QtCore.Qt.AlignCenter) 88 | self.lineEdit_scrlbr2.setObjectName("lineEdit_scrlbr2") 89 | self.horizontalLayout_2.addWidget(self.lineEdit_scrlbr2) 90 | spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 91 | self.horizontalLayout_2.addItem(spacerItem3) 92 | self.sldr_fig2.addLayout(self.horizontalLayout_2) 93 | self.hz_lyt_sliders.addLayout(self.sldr_fig2) 94 | self.sldr_fig3 = QtWidgets.QVBoxLayout() 95 | self.sldr_fig3.setObjectName("sldr_fig3") 96 | self.scrlbr_fig3 = QtWidgets.QScrollBar(self.centralwidget) 97 | self.scrlbr_fig3.setOrientation(QtCore.Qt.Horizontal) 98 | self.scrlbr_fig3.setObjectName("scrlbr_fig3") 99 | self.sldr_fig3.addWidget(self.scrlbr_fig3) 100 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 101 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 102 | self.horizontalLayout_9 = QtWidgets.QHBoxLayout() 103 | self.horizontalLayout_9.setObjectName("horizontalLayout_9") 104 | spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 105 | self.horizontalLayout_9.addItem(spacerItem4) 106 | self.label_3 = QtWidgets.QLabel(self.centralwidget) 107 | self.label_3.setObjectName("label_3") 108 | self.horizontalLayout_9.addWidget(self.label_3) 109 | self.horizontalLayout_3.addLayout(self.horizontalLayout_9) 110 | self.lineEdit_scrlbr3 = QtWidgets.QLineEdit(self.centralwidget) 111 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 112 | sizePolicy.setHorizontalStretch(0) 113 | sizePolicy.setVerticalStretch(0) 114 | sizePolicy.setHeightForWidth(self.lineEdit_scrlbr3.sizePolicy().hasHeightForWidth()) 115 | self.lineEdit_scrlbr3.setSizePolicy(sizePolicy) 116 | self.lineEdit_scrlbr3.setAlignment(QtCore.Qt.AlignCenter) 117 | self.lineEdit_scrlbr3.setObjectName("lineEdit_scrlbr3") 118 | self.horizontalLayout_3.addWidget(self.lineEdit_scrlbr3) 119 | spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 120 | self.horizontalLayout_3.addItem(spacerItem5) 121 | self.sldr_fig3.addLayout(self.horizontalLayout_3) 122 | self.hz_lyt_sliders.addLayout(self.sldr_fig3) 123 | self.verticalLayout.addLayout(self.hz_lyt_sliders) 124 | self.hz_lyt_btns = QtWidgets.QHBoxLayout() 125 | self.hz_lyt_btns.setObjectName("hz_lyt_btns") 126 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout() 127 | self.horizontalLayout_5.setObjectName("horizontalLayout_5") 128 | self.checkBox_lockcmap = QtWidgets.QCheckBox(self.centralwidget) 129 | self.checkBox_lockcmap.setObjectName("checkBox_lockcmap") 130 | self.horizontalLayout_5.addWidget(self.checkBox_lockcmap) 131 | self.hz_lyt_btns.addLayout(self.horizontalLayout_5) 132 | self.verticalLayout.addLayout(self.hz_lyt_btns) 133 | self.verticalLayout_2.addLayout(self.verticalLayout) 134 | VolumeSlicer.setCentralWidget(self.centralwidget) 135 | self.menubar = QtWidgets.QMenuBar(VolumeSlicer) 136 | self.menubar.setGeometry(QtCore.QRect(0, 0, 1800, 22)) 137 | self.menubar.setObjectName("menubar") 138 | VolumeSlicer.setMenuBar(self.menubar) 139 | self.statusbar = QtWidgets.QStatusBar(VolumeSlicer) 140 | self.statusbar.setObjectName("statusbar") 141 | VolumeSlicer.setStatusBar(self.statusbar) 142 | 143 | self.retranslateUi(VolumeSlicer) 144 | QtCore.QMetaObject.connectSlotsByName(VolumeSlicer) 145 | 146 | def retranslateUi(self, VolumeSlicer): 147 | _translate = QtCore.QCoreApplication.translate 148 | VolumeSlicer.setWindowTitle(_translate("VolumeSlicer", "Volume Slicer")) 149 | self.label.setText(_translate("VolumeSlicer", "X = ")) 150 | self.label_2.setText(_translate("VolumeSlicer", "Y = ")) 151 | self.label_3.setText(_translate("VolumeSlicer", "Z = ")) 152 | self.checkBox_lockcmap.setText(_translate("VolumeSlicer", "Lock Colormap")) 153 | 154 | -------------------------------------------------------------------------------- /genfire/gui/VolumeSlicer_MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | VolumeSlicer 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1800 10 | 800 11 | 12 | 13 | 14 | Volume Slicer 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Qt::Horizontal 41 | 42 | 43 | false 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Qt::Horizontal 55 | 56 | 57 | 58 | 40 59 | 20 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | X = 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 0 78 | 0 79 | 80 | 81 | 82 | Qt::AlignCenter 83 | 84 | 85 | 86 | 87 | 88 | 89 | Qt::Horizontal 90 | 91 | 92 | 93 | 40 94 | 20 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Qt::Horizontal 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Horizontal 120 | 121 | 122 | 123 | 40 124 | 20 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Y = 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 0 143 | 0 144 | 145 | 146 | 147 | Qt::AlignCenter 148 | 149 | 150 | 151 | 152 | 153 | 154 | Qt::Horizontal 155 | 156 | 157 | 158 | 40 159 | 20 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | Qt::Horizontal 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | Qt::Horizontal 185 | 186 | 187 | 188 | 40 189 | 20 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | Z = 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 0 208 | 0 209 | 210 | 211 | 212 | Qt::AlignCenter 213 | 214 | 215 | 216 | 217 | 218 | 219 | Qt::Horizontal 220 | 221 | 222 | 223 | 40 224 | 20 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | Lock Colormap 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 0 258 | 0 259 | 1800 260 | 22 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /genfire/gui/__init__.py: -------------------------------------------------------------------------------- 1 | from . import utility 2 | from . import VolumeSlicer 3 | from . import launch 4 | from . import ProjectionCalculator 5 | from . import GENFIRE_MainWindow 6 | from . import ProjectionCalculator_MainWindow 7 | from . import CalculateProjectionSeries_Dialog 8 | from . import VolumeSlicer_MainWindow 9 | -------------------------------------------------------------------------------- /genfire/gui/calculateprojectionseries_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CalculateProjectionSeries_Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 762 10 | 382 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Dialog 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Filename Containing Euler Angles 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 500 44 | 0 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Browse 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Qt::Horizontal 62 | 63 | 64 | 65 | 66 | 67 | 68 | Generate Euler Angles 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Phi 80 | 81 | 82 | 83 | 84 | 85 | 86 | Theta (Tilt) 87 | 88 | 89 | 90 | 91 | 92 | 93 | Psi 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 0 110 | 0 111 | 112 | 113 | 114 | 6 115 | 116 | 117 | Qt::AlignCenter 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 0 128 | 0 129 | 130 | 131 | 132 | 6 133 | 134 | 135 | Qt::AlignCenter 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 0 146 | 0 147 | 148 | 149 | 150 | 151 | 10 152 | 20 153 | 154 | 155 | 156 | 157 | 2 158 | 0 159 | 160 | 161 | 162 | 6 163 | 164 | 165 | Qt::AlignCenter 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | Start 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | Qt::Horizontal 186 | 187 | 188 | 189 | 40 190 | 20 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 0 202 | 0 203 | 204 | 205 | 206 | 6 207 | 208 | 209 | Qt::AlignCenter 210 | 211 | 212 | 213 | 214 | 215 | 216 | Step 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | Qt::Horizontal 226 | 227 | 228 | 229 | 40 230 | 20 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | Qt::Horizontal 243 | 244 | 245 | 246 | 40 247 | 20 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 0 259 | 0 260 | 261 | 262 | 263 | 6 264 | 265 | 266 | Qt::AlignCenter 267 | 268 | 269 | 270 | 271 | 272 | 273 | Stop 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | Qt::Horizontal 283 | 284 | 285 | 286 | 40 287 | 20 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | Save Angles 304 | 305 | 306 | 307 | 308 | 309 | 310 | Qt::Horizontal 311 | 312 | 313 | 314 | 40 315 | 20 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | Projection Filename 328 | 329 | 330 | true 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 0 339 | 0 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | *.mrc, *.npy, or *.mat 353 | 354 | 355 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 356 | 357 | 358 | 359 | 360 | 361 | 362 | Qt::Horizontal 363 | 364 | 365 | 366 | 367 | 368 | 369 | Qt::Horizontal 370 | 371 | 372 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | lineEdit_angleFile 384 | btn_selectAngleFile 385 | lineEdit_phi 386 | lineEdit_thetaStart 387 | lineEdit_psi 388 | lineEdit_outputFilename 389 | 390 | 391 | 392 | 393 | buttonBox 394 | accepted() 395 | CalculateProjectionSeries_Dialog 396 | accept() 397 | 398 | 399 | 248 400 | 254 401 | 402 | 403 | 157 404 | 274 405 | 406 | 407 | 408 | 409 | buttonBox 410 | rejected() 411 | CalculateProjectionSeries_Dialog 412 | reject() 413 | 414 | 415 | 316 416 | 260 417 | 418 | 419 | 286 420 | 274 421 | 422 | 423 | 424 | 425 | 426 | -------------------------------------------------------------------------------- /genfire/gui/utility.py: -------------------------------------------------------------------------------- 1 | """ 2 | * genfire.gui.utility * 3 | 4 | The gui utility function module 5 | 6 | 7 | Author: Alan (AJ) Pryor, Jr. 8 | Jianwei (John) Miao Coherent Imaging Group 9 | University of California, Los Angeles 10 | Copyright 2015-2016. All rights reserved. 11 | """ 12 | 13 | from PyQt5 import QtCore, QtGui 14 | import sys 15 | 16 | # strings are very different objects in Python 2 and 3, so a little modification of these 17 | # helper functions is necessary dependent on the version 18 | if sys.version_info >=(3,0): 19 | def toString(string): 20 | return str(string) 21 | def toQString(string): 22 | return str(string) 23 | def toFloat(string): 24 | return float(string) 25 | def toInt(value): 26 | return int(value) 27 | else: #python 2 28 | import PyQt5.QtCore 29 | def toString(string): 30 | if isinstance(string,QtCore.QString): 31 | string = unicode(string.toUtf8(),encoding='UTF-8') 32 | return string 33 | def toQString(string): 34 | return PyQt5.QtCore.QString(str(string)) 35 | def toFloat(value): 36 | if isinstance(value,QtCore.QString): 37 | return value.toFloat()[0] 38 | else: 39 | return float(value) 40 | def toInt(value): 41 | if isinstance(value,QtCore.QString): 42 | return value.toInt()[0] 43 | else: 44 | return int(value) 45 | -------------------------------------------------------------------------------- /genfire/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | * genfire.main * 3 | 4 | The primary control module for running GENFIRE reconstructions. 5 | 6 | 7 | Author: Alan (AJ) Pryor, Jr. 8 | Jianwei (John) Miao Coherent Imaging Group 9 | University of California, Los Angeles 10 | Copyright 2015-2016. All rights reserved. 11 | """ 12 | 13 | from __future__ import division 14 | import numpy as np 15 | import genfire 16 | import sys 17 | import os 18 | from genfire.reconstruct import ReconstructionParameters 19 | 20 | 21 | def main_InteractivelySetParameters(): 22 | ####################################################################################################################### 23 | ############################################### User Parameters ###################################################### 24 | ####################################################################################################################### 25 | 26 | # GENFIRE's reconstruction parameters can be edited here by the user and run interactively, any inputs provided 27 | # by either the command line or the GUI will override these momentarily 28 | 29 | filename_projections = '../data/projections.mat' #filename of projections, which should be size NxNxN_projections where N_projections is the number of projections 30 | filename_angles = '../data/angles.mat' #angles can be either a 1xN_projections array containing a single tilt series, or 3xN_projections array containing 3 Euler angles for each projections in the form [phi;theta;psi] 31 | filename_support = '../data/support60.mat' #NxNxN binary array specifying a region of 1's in which the reconstruction can exist 32 | filename_initialObject = None #initial object to use in reconstruction; set to None to provide no initial guess 33 | filename_results = 'GENFIRE_rec.mrc' #filename to save results 34 | resolutionExtensionSuppressionState = 2 # 1) Turn on resolution extension/suppression, 2) No resolution extension/suppression, 3) Just resolution extension 35 | 36 | numIterations = 100 #number of iterations to run in iterative reconstruction 37 | oversamplingRatio = 3 #input projections will be padded internally to match this oversampling ratio. If you prepad your projections, set this to 1 38 | interpolationCutoffDistance = 0.7 #radius of spherical interpolation kernel (in pixels) within which to include measured datapoints 39 | doYouWantToDisplayFigure = True 40 | displayFigure = genfire.reconstruct.DisplayFigure() 41 | displayFigure.DisplayFigureON = doYouWantToDisplayFigure 42 | calculateRFree = True 43 | if filename_support is None: 44 | useDefaultSupport = True 45 | else: 46 | useDefaultSupport = False 47 | 48 | reconstruction_parameters = ReconstructionParameters() 49 | reconstruction_parameters.projections = filename_projections 50 | reconstruction_parameters.eulerAngles = filename_angles 51 | reconstruction_parameters.support = filename_support 52 | reconstruction_parameters.interpolationCutoffDistance = interpolationCutoffDistance 53 | reconstruction_parameters.numIterations = numIterations 54 | reconstruction_parameters.oversamplingRatio = oversamplingRatio 55 | reconstruction_parameters.displayFigure = displayFigure 56 | reconstruction_parameters.calculateRfree = calculateRFree 57 | reconstruction_parameters.resolutionExtensionSuppressionState = resolutionExtensionSuppressionState 58 | reconstruction_parameters.useDefaultSupport = useDefaultSupport 59 | if os.path.isfile(filename_results): # If a valid initial object was provided, use it 60 | reconstruction_parameters.initialObject = filename_results 61 | 62 | main(reconstruction_parameters) 63 | 64 | def main(reconstruction_parameters): 65 | import genfire.fileio 66 | 67 | filename_projections = reconstruction_parameters.projections 68 | filename_angles = reconstruction_parameters.eulerAngles 69 | filename_support = reconstruction_parameters.support 70 | filename_results = reconstruction_parameters.resultsFilename 71 | numIterations = reconstruction_parameters.numIterations 72 | oversamplingRatio = reconstruction_parameters.oversamplingRatio 73 | interpolationCutoffDistance = reconstruction_parameters.interpolationCutoffDistance 74 | displayFigure = reconstruction_parameters.displayFigure 75 | resolutionExtensionSuppressionState = reconstruction_parameters.resolutionExtensionSuppressionState 76 | calculateRFree = reconstruction_parameters.calculateRfree 77 | useDefaultSupport = reconstruction_parameters.useDefaultSupport 78 | use_positivity = reconstruction_parameters.constraintPositivity 79 | use_support = reconstruction_parameters.constraintSupport 80 | gridding_method = reconstruction_parameters.griddingMethod 81 | enforceResolutionCircle = reconstruction_parameters.enforceResolutionCircle 82 | permitMultipleGridding = reconstruction_parameters.permitMultipleGridding 83 | 84 | if reconstruction_parameters.isInitialObjectDefined: 85 | filename_initialObject = reconstruction_parameters.initialObject 86 | else: 87 | filename_initialObject = None 88 | 89 | ### begin reconstruction ### 90 | projections = genfire.fileio.loadProjections(filename_projections) # load projections into a 3D numpy array 91 | 92 | # get dimensions of array and determine the array size after padding 93 | dims = np.shape(projections) 94 | paddedDim = dims[0] * oversamplingRatio 95 | padding = int((paddedDim-dims[0])/2) 96 | 97 | # load the support, or generate one if none was provided 98 | if useDefaultSupport or filename_support == "": 99 | support = np.ones((dims[0],dims[0],dims[0]),dtype=float) 100 | else: 101 | support = (genfire.fileio.readVolume(filename_support) != 0).astype(bool) 102 | 103 | displayFigure.reconstructionDisplayWindowSize = np.shape(support) # this is used to show the central region of reconstruction 104 | 105 | # now zero-pad to match the oversampling ratio 106 | support = np.pad(support,((padding,padding),(padding,padding),(padding,padding)),'constant') 107 | projections = np.pad(projections,((padding,padding),(padding,padding),(0,0)),'constant') 108 | 109 | #load initial object, or initialize it to zeros if none was given 110 | if filename_initialObject is not None and os.path.isfile(filename_initialObject): 111 | initialObject = genfire.fileio.readVolume(filename_initialObject) 112 | initialObject = np.pad(initialObject,((padding,padding),(padding,padding),(padding,padding)),'constant') 113 | else: 114 | initialObject = np.zeros_like(support) 115 | 116 | # load angles and check that the dimensions match the number of provided projections and that they 117 | # are either 1 x num_projections or 3 x num_projections 118 | angles = genfire.fileio.loadAngles(filename_angles) 119 | if np.shape(angles)[1] > 3: 120 | raise ValueError("Error! Dimension of angles incorrect.") 121 | if np.shape(angles)[1] == 1: 122 | tmp = np.zeros([np.shape(angles)[1], 3]) 123 | tmp[1, :] = angles 124 | angles = tmp 125 | del tmp 126 | 127 | # grid the projections 128 | if gridding_method == "DFT": 129 | measuredK = genfire.reconstruct.fillInFourierGrid_DFT(projections, angles, interpolationCutoffDistance, enforceResolutionCircle) 130 | else: 131 | measuredK = genfire.reconstruct.fillInFourierGrid(projections, angles, interpolationCutoffDistance, enforceResolutionCircle, permitMultipleGridding) 132 | 133 | # the grid is assembled with the origin at the geometric center of the array, but for efficiency in the 134 | # iterative algorithm the origin is shifted to array position [0,0,0] to avoid unnecessary fftshift calls 135 | measuredK = np.fft.ifftshift(measuredK) 136 | 137 | # create a map of the spatial frequency to be used to control resolution extension/suppression behavior 138 | K_indices = genfire.utility.generateKspaceIndices(support) 139 | K_indices = np.fft.fftshift(K_indices) 140 | resolutionIndicators = np.zeros_like(K_indices) 141 | resolutionIndicators[measuredK != 0] = 1-K_indices[measuredK != 0] 142 | 143 | # if calculating Rfree, setup some infrastructure 144 | if calculateRFree: 145 | R_freeInd_complexX = [] 146 | R_freeInd_complexY = [] 147 | R_freeInd_complexZ = [] 148 | R_freeVals_complex = [] 149 | shell_thickness_pixels = 1 # pixel thickness of an individual shell of Rfree points 150 | numberOfBins = int(round(dims[0]/2/shell_thickness_pixels)) # number of frequency bins. Rfree will be tracked within each shell separately 151 | percentValuesForRfree = 0.05 # percentage of measured points to withhold 152 | spatialFrequencyForRfree = np.linspace(0,1,numberOfBins+1) 153 | K_indicesSmall =(K_indices)[:, :, 0:(np.shape(measuredK)[-1]//2+1)] 154 | 155 | for shellNum in range(0,numberOfBins): 156 | # collect relevant points 157 | measuredPointInd_complex = np.where((measuredK[:, :, 0:(np.shape(measuredK)[-1]//2+1)] != 0) & (K_indicesSmall>=(spatialFrequencyForRfree[shellNum])) & (K_indicesSmall<=(spatialFrequencyForRfree[shellNum+1]))) 158 | 159 | # randomly shuffle 160 | shuffledPoints = np.random.permutation(np.shape(measuredPointInd_complex)[1]) 161 | measuredPointInd_complex = (measuredPointInd_complex[0][shuffledPoints], measuredPointInd_complex[1][shuffledPoints], measuredPointInd_complex[2][shuffledPoints]) 162 | 163 | # determine how many values to take 164 | cutoffInd_complex = np.floor(np.shape(measuredPointInd_complex)[1] * percentValuesForRfree).astype(int) 165 | 166 | # collect the Rfree values and coordinates 167 | R_freeInd_complexX.append(measuredPointInd_complex[0][:cutoffInd_complex]) 168 | R_freeInd_complexY.append(measuredPointInd_complex[1][:cutoffInd_complex]) 169 | R_freeInd_complexZ.append(measuredPointInd_complex[2][:cutoffInd_complex]) 170 | R_freeVals_complex.append(measuredK[R_freeInd_complexX[shellNum], R_freeInd_complexY[shellNum], R_freeInd_complexZ[shellNum] ]) 171 | 172 | # delete the points from the measured data 173 | measuredK[R_freeInd_complexX[shellNum], R_freeInd_complexY[shellNum], R_freeInd_complexZ[shellNum]] = 0 174 | 175 | # create tuple of coordinates 176 | R_freeInd_complex = [[R_freeInd_complexX], [R_freeInd_complexY], [R_freeInd_complexZ]] 177 | del R_freeInd_complexX 178 | del R_freeInd_complexY 179 | del R_freeInd_complexZ 180 | else: 181 | R_freeInd_complex = [] 182 | R_freeVals_complex = [] 183 | 184 | if resolutionExtensionSuppressionState==1: # resolution extension/suppression 185 | constraintEnforcementDelayIndicators = np.array(np.concatenate((np.arange(0.95, -.25, -0.15), np.arange(-0.15, .95, .1)), axis=0)) 186 | elif resolutionExtensionSuppressionState==2:# no resolution extension or suppression 187 | constraintEnforcementDelayIndicators = np.array([-999, -999, -999, -999]) 188 | elif resolutionExtensionSuppressionState==3:# resolution extension only 189 | constraintEnforcementDelayIndicators = np.concatenate((np.arange(0.95, -.15, -0.15),[-0.15, -0.15, -0.15])) 190 | else: 191 | print("Warning! Input resolutionExtensionSuppressionState does not match an available option. Deactivating dynamic constraint enforcement and continuing.\n") 192 | constraintEnforcementDelayIndicators = np.array([-999, -999, -999, -999]) 193 | 194 | reconstructionOutputs = genfire.reconstruct.reconstruct(numIterations, np.fft.fftshift(initialObject), np.fft.fftshift(support), (measuredK)[:, :, 0:(np.shape(measuredK)[-1] // 2 + 1)], (resolutionIndicators)[:, :, 0:(np.shape(measuredK)[-1] // 2 + 1)], constraintEnforcementDelayIndicators, R_freeInd_complex, R_freeVals_complex, displayFigure, use_positivity, use_support) 195 | 196 | # reclaim original array size. ncBig is center of oversampled array, and n2 is the half-width of original array 197 | ncBig = paddedDim//2 198 | n2 = dims[0]//2 199 | reconstructionOutputs['reconstruction'] = reconstructionOutputs['reconstruction'][ncBig-n2:ncBig+n2,ncBig-n2:ncBig+n2,ncBig-n2:ncBig+n2] 200 | genfire.fileio.saveResults(reconstructionOutputs, filename_results) 201 | 202 | if __name__ == "__main__" and len(sys.argv) == 1: 203 | print ("starting with user parameters") 204 | main_InteractivelySetParameters() 205 | elif __name__ == "__main__": 206 | if len(sys.argv) > 1: # Parse inputs provided either from the GUI or from the command line 207 | inputArgumentOptions = {"-p" : "filename_projections", 208 | "-a" : "filename_angles", 209 | "-s" : "filename_support", 210 | "-o" : "filename_results", 211 | "-i" : "filename_initialObject", 212 | "-r" : "resolutionExtensionSuppressionState", 213 | "-it": "numIterations", 214 | "-or": "oversamplingRatio", 215 | "-t" : "interpolationCutoffDistance", 216 | "-d" : "displayFigure", 217 | "-rf": "calculateRFree" 218 | } 219 | print (sys.argv[:]) 220 | if len(sys.argv)%2==0: 221 | raise Exception("Number of input options and input arguments does not match!") 222 | for argumentNum in range(1,len(sys.argv),2): 223 | print (inputArgumentOptions[sys.argv[argumentNum]]) 224 | print (sys.argv[argumentNum+1]) 225 | print (inputArgumentOptions[sys.argv[argumentNum]] + "=" + sys.argv[argumentNum+1]) 226 | 227 | 228 | exec(inputArgumentOptions[sys.argv[argumentNum]] + "= '" + sys.argv[argumentNum+1] +"'") 229 | print("Setting argument %s from option %s equal to GENFIRE parameter %s " % (sys.argv[argumentNum+1],sys.argv[argumentNum], inputArgumentOptions[sys.argv[argumentNum]] )) 230 | 231 | numIterations = int(numIterations) 232 | # displayFigure = bool(displayFigure) 233 | doYouWantToDisplayFigure = bool(displayFigure) 234 | displayFigure = genfire.reconstruct.DisplayFigure() 235 | displayFigure.DisplayFigureON = doYouWantToDisplayFigure 236 | oversamplingRatio = float(oversamplingRatio) 237 | resolutionExtensionSuppressionState = int(resolutionExtensionSuppressionState) 238 | calculateRFree = bool(calculateRFree) 239 | try: 240 | main(filename_projections, 241 | filename_angles, 242 | filename_support, 243 | filename_results, 244 | numIterations, 245 | oversamplingRatio, 246 | interpolationCutoffDistance, 247 | resolutionExtensionSuppressionState, 248 | displayFigure, 249 | calculateRFree, 250 | filename_initialObject) 251 | except (NameError, IOError): 252 | main(filename_projections, 253 | filename_angles, 254 | filename_support, 255 | filename_results, 256 | numIterations, 257 | oversamplingRatio, 258 | interpolationCutoffDistance, 259 | resolutionExtensionSuppressionState, 260 | displayFigure, 261 | calculateRFree) 262 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | matplotlib 3 | scipy 4 | cycler 5 | Pillow 6 | pytz 7 | python-dateutil 8 | six 9 | 10 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages,setup, Extension 2 | from subprocess import call 3 | import sys 4 | 5 | setup( 6 | name = "genfire", 7 | packages = find_packages(), 8 | version = "1.1.11", 9 | description = "GENeralized Fourier Iterative REconstruction", 10 | author = "Alan (AJ) Pryor, Jr.", 11 | author_email = "apryor6@gmail.com", 12 | install_requires = ['Pillow>=4.1.1','numpy>=1.12.1','matplotlib>=2.0.2','scipy>=0.19.0', 'pyparsing>=2.2.0','six>=1.10.0', 'PyQt5>=5.5.0'], 13 | scripts = ['bin/genfire'] 14 | ) 15 | 16 | 17 | --------------------------------------------------------------------------------