comparison spyboat_cli.py @ 3:4d7f30a7e2f6 draft

"planemo upload commit d070f1ba04a5141a65487f45b29c22767639e44b"
author gregor.m
date Tue, 24 Nov 2020 13:06:26 +0000
parents
children a4c6fcf2c456
comparison
equal deleted inserted replaced
2:c59d1373230e 3:4d7f30a7e2f6
1 #!/usr/bin/env python
2
3 ## Gets interfaced by Galaxy or can be used for bash scripting
4 import argparse
5 import sys, os
6 import logging
7
8 from skimage import io
9 from numpy import float32
10
11 import spyboat
12 import output_report
13
14 logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
15 logger = logging.getLogger('wrapper')
16
17 # ----------command line parameters ---------------
18
19 parser = argparse.ArgumentParser(description='Process some arguments.')
20
21 # I/O
22 parser.add_argument('--input_path', help="Input movie location", required=True)
23 parser.add_argument('--phase_out', help='Phase output file name', required=True)
24 parser.add_argument('--period_out', help='Period output file name', required=True)
25 parser.add_argument('--power_out', help='Power output file name', required=True)
26 parser.add_argument('--amplitude_out', help='Amplitude output file name', required=True)
27 parser.add_argument('--preprocessed_out', help="Preprocessed-input output file name, 'None'", required=False)
28
29
30 # (Optional) Multiprocessing
31
32 parser.add_argument('--ncpu', help='Number of processors to use',
33 required=False, type=int, default=1)
34
35 # Optional spatial downsampling
36 parser.add_argument('--rescale', help='Rescale the image by a factor given in %%, None means no rescaling',
37 required=False, type=int)
38 # Optional Gaussian smoothing
39 parser.add_argument('--gauss_sigma', help='Gaussian smoothing parameter, None means no smoothing', required=False, type=float)
40
41 # Wavelet Analysis Parameters
42 parser.add_argument('--dt', help='Sampling interval', required=True, type=float)
43 parser.add_argument('--Tmin', help='Smallest period', required=True, type=float)
44 parser.add_argument('--Tmax', help='Biggest period', required=True, type=float)
45 parser.add_argument('--nT', help='Number of periods to scan for', required=True, type=int)
46
47 parser.add_argument('--Tcutoff', help='Sinc cut-off period, disables detrending if not set', required=False, type=float)
48 parser.add_argument('--win_size', help='Sliding window size for amplitude normalization, None means no normalization',
49 required=False, type=float)
50
51 # Optional masking
52 parser.add_argument('--masking', help="Set to either 'dynamic', 'static' or 'None' which is the default", default='None', required=False, type=str)
53
54 parser.add_argument('--mask_frame',
55 help="The frame of the input movie to create a static mask from, needs masking set to 'static'",
56 required=False, type=int)
57
58
59 parser.add_argument('--mask_thresh', help='The threshold of the mask, all pixels with less than this value get masked (if masking enabled).',
60 required=False, type=float,
61 default=0)
62
63 # output html report/snapshots
64 parser.add_argument('--html_fname', help="Name of the html report.",
65 default='OutputReport.html', required=False, type=str)
66
67 parser.add_argument('--report_img_path', help="For the html report, to be set in Galaxy. Without galaxy leave at cwd!", default='.', required=False, type=str)
68
69 parser.add_argument('--version', action='version', version='0.1.0')
70
71 arguments = parser.parse_args()
72
73 logger.info("Received following arguments:")
74 for arg in vars(arguments):
75 logger.info(f'{arg} -> {getattr(arguments, arg)}')
76
77 # ------------Read the input----------------------------------------
78 try:
79 movie = spyboat.open_tif(arguments.input_path)
80 except FileNotFoundError:
81 logger.critical(f"Couldn't open {arguments.input_path}, check movie storage directory!")
82
83 sys.exit(1)
84
85 # -------- Do (optional) spatial downsampling ---------------------------
86
87 scale_factor = arguments.rescale
88
89 # defaults to None
90 if not scale_factor:
91 logger.info('No downsampling requested..')
92
93 elif 0 < scale_factor < 100:
94 logger.info(f'Downsampling the movie to {scale_factor:d}% of its original size..')
95 movie = spyboat.down_sample(movie, scale_factor / 100)
96 else:
97 raise ValueError('Scale factor must be between 0 and 100!')
98
99 # -------- Do (optional) pre-smoothing -------------------------
100 # note that downsampling already is a smoothing operation..
101
102 # check if pre-smoothing requested
103 if not arguments.gauss_sigma:
104 logger.info('No pre-smoothing requested..')
105 else:
106 logger.info(f'Pre-smoothing the movie with Gaussians, sigma = {arguments.gauss_sigma:.2f}..')
107
108 movie = spyboat.gaussian_blur(movie, arguments.gauss_sigma)
109
110 # ----- Set up Masking before processing ----
111
112 mask = None
113 if arguments.masking == 'static':
114 if not arguments.mask_frame:
115 logger.critical("Frame number for static masking is missing!")
116 sys.exit(1)
117
118 if (arguments.mask_frame > movie.shape[0]) or (arguments.mask_frame < 0):
119 logger.critical(f'Requested frame does not exist, input only has {movie.shape[0]} frames.. exiting')
120 sys.exit(1)
121
122 else:
123 logger.info(f'Creating static mask from frame {arguments.mask_frame} with threshold {arguments.mask_thresh}')
124 mask = spyboat.create_static_mask(movie, arguments.mask_frame,
125 arguments.mask_thresh)
126 elif arguments.masking == 'dynamic':
127 logger.info(f'Creating dynamic mask with threshold {arguments.mask_thresh}')
128 mask = spyboat.create_dynamic_mask(movie, arguments.mask_thresh)
129
130 else:
131 logger.info('No masking requested..')
132
133 # ------ Retrieve wavelet parameters ---------------------------
134
135 Wkwargs = {'dt': arguments.dt,
136 'Tmin': arguments.Tmin,
137 'Tmax': arguments.Tmax,
138 'nT': arguments.nT,
139 'T_c' : arguments.Tcutoff, # defaults to None
140 'win_size' : arguments.win_size # defaults to None
141 }
142
143 # --- start parallel processing ---
144
145 results = spyboat.run_parallel(movie, arguments.ncpu, **Wkwargs)
146
147 # --- masking? ---
148
149 if mask is not None:
150 # mask all output movies (in place!)
151 for key in results:
152 logger.info(f'Masking {key}')
153 spyboat.apply_mask(results[key], mask, fill_value=-1)
154
155 # --- Produce Output HTML Report Figures/png's ---
156
157 # create the directory, yes we have to do that ourselves :)
158 # galaxy then magically renders the html from that directory
159 try:
160
161 if arguments.report_img_path != '.':
162 logger.info(f'Creating report directory {arguments.report_img_path}')
163 os.mkdir(arguments.report_img_path)
164
165 # make 6 times 4 snapshots each
166 Nsnap = 6
167 NFrames = movie.shape[0]
168 # show only frames at least one Tmin
169 # away from the edge (-effects)
170 start_frame = int(Wkwargs['Tmin']/Wkwargs['dt'])
171
172 if (start_frame > NFrames//2):
173 logger.warning("Smallest period already is larger than half the observation time!")
174 # set to 0 in this case
175 start_frame = 0
176
177 frame_increment = int( (NFrames - 2*start_frame) / Nsnap)
178 snapshot_frames = range(start_frame, NFrames - start_frame, frame_increment)
179
180 for snapshot_frame in snapshot_frames:
181 output_report.produce_snapshots(movie, results, snapshot_frame, Wkwargs, img_path=arguments.report_img_path)
182
183 output_report.produce_distr_plots(results, Wkwargs, img_path=arguments.report_img_path)
184
185 output_report.create_html(snapshot_frames, arguments.html_fname)
186
187 except FileExistsError as e:
188 logger.critical(f"Could not create html report directory: {repr(e)}")
189
190
191 # --- save out result movies ---
192
193 # save phase movie
194 io.imsave(arguments.phase_out, results['phase'], plugin="tifffile")
195 logger.info(f'Written {arguments.phase_out}')
196 # save period movie
197 io.imsave(arguments.period_out, results['period'], plugin="tifffile")
198 logger.info(f'Written {arguments.period_out}')
199 # save power movie
200 io.imsave(arguments.power_out, results['power'], plugin="tifffile")
201 logger.info(f'Written {arguments.power_out}')
202 # save amplitude movie
203 io.imsave(arguments.amplitude_out, results['amplitude'], plugin="tifffile")
204 logger.info(f'Written {arguments.amplitude_out}')
205
206 # save out the probably pre-processed (scaled and blurred) input movie for
207 # direct comparison to results and coordinate mapping etc.
208 if arguments.preprocessed_out:
209 io.imsave(arguments.preprocessed_out, movie, plugin='tifffile')
210 logger.info(f'Written {arguments.preprocessed_out}')