Mercurial > repos > rv43 > tomo
comparison tomo.py @ 61:75dd6e15f628 draft
"planemo upload for repository https://github.com/rolfverberg/galaxytools commit 47b7bc203de6eac4d3e081b1fae8acb352f54b55"
author | rv43 |
---|---|
date | Wed, 17 Aug 2022 12:11:20 +0000 |
parents | 26f99fdd8d61 |
children | 98a83f03d91b |
comparison
equal
deleted
inserted
replaced
60:52db7707ff48 | 61:75dd6e15f628 |
---|---|
43 from fit import Fit | 43 from fit import Fit |
44 #from msnctools.general import illegal_value, is_int, is_num, is_index_range, get_trailing_int, \ | 44 #from msnctools.general import illegal_value, is_int, is_num, is_index_range, get_trailing_int, \ |
45 from general import illegal_value, is_int, is_num, is_index_range, get_trailing_int, \ | 45 from general import illegal_value, is_int, is_num, is_index_range, get_trailing_int, \ |
46 input_int, input_num, input_yesno, input_menu, findImageFiles, loadImageStack, clearPlot, \ | 46 input_int, input_num, input_yesno, input_menu, findImageFiles, loadImageStack, clearPlot, \ |
47 draw_mask_1d, quickPlot, clearImshow, quickImshow, combine_tiffs_in_h5, Config | 47 draw_mask_1d, quickPlot, clearImshow, quickImshow, combine_tiffs_in_h5, Config |
48 from general import selectArrayBounds,selectImageRange, selectImageBounds | 48 from general import selectImageRange, selectImageBounds |
49 | 49 |
50 # the following tomopy routines don't run with more than 24 cores on Galaxy-Dev | 50 # the following tomopy routines don't run with more than 24 cores on Galaxy-Dev |
51 # - tomopy.find_center_vo | 51 # - tomopy.find_center_vo |
52 # - tomopy.prep.stripe.remove_stripe_fw | 52 # - tomopy.prep.stripe.remove_stripe_fw |
53 num_core_tomopy_limit = 24 | 53 num_core_tomopy_limit = 24 |
427 # Validate input parameters | 427 # Validate input parameters |
428 if config_file is not None and not os.path.isfile(config_file): | 428 if config_file is not None and not os.path.isfile(config_file): |
429 raise OSError(f'Invalid config_file input {config_file} {type(config_file)}') | 429 raise OSError(f'Invalid config_file input {config_file} {type(config_file)}') |
430 if config_dict is not None and not isinstance(config_dict, dict): | 430 if config_dict is not None and not isinstance(config_dict, dict): |
431 raise ValueError(f'Invalid config_dict input {config_dict} {type(config_dict)}') | 431 raise ValueError(f'Invalid config_dict input {config_dict} {type(config_dict)}') |
432 if config_out is not None: | 432 if self.config_out is not None and not isinstance(self.config_out, str): |
433 if isinstance(config_out, str): | 433 raise OSError(f'Invalid config_out input {self.config_out} {type(self.config_out)}') |
434 if isinstance(log_stream, str): | |
435 path = os.path.split(log_stream)[0] | |
436 if path and not os.path.isdir(path): | |
437 raise OSError(f'Invalid log_stream path') | |
438 else: | |
439 raise OSError(f'Invalid config_out input {config_out} {type(config_out)}') | |
440 if not os.path.isdir(output_folder): | 434 if not os.path.isdir(output_folder): |
441 os.mkdir(os.path.abspath(output_folder)) | 435 os.mkdir(os.path.abspath(output_folder)) |
442 if isinstance(log_stream, str): | 436 if isinstance(log_stream, str): |
443 path = os.path.split(log_stream)[0] | 437 path = os.path.split(log_stream)[0] |
444 if path and not os.path.isdir(path): | 438 if path and not os.path.isdir(path): |
445 raise OSError(f'Invalid log_stream path') | 439 raise OSError(f'Invalid log_stream path') |
446 if not os.path.isabs(path): | 440 if not os.path.isabs(path): |
447 log_stream = f'{output_folder}/{log_stream}' | 441 log_stream = f'{output_folder}/{log_stream}' |
448 if not isinstance(galaxy_flag, bool): | 442 if not isinstance(galaxy_flag, bool): |
449 raise ValueError(f'Invalid galaxy_flag input {galaxy_flag} {type(galaxy_flag)}') | 443 raise ValueError(f'Invalid galaxy_flag input {galaxy_flag} {type(galaxy_flag)}') |
450 if not isinstance(test_mode, bool): | 444 if not isinstance(self.test_mode, bool): |
451 raise ValueError(f'Invalid test_mode input {test_mode} {type(test_mode)}') | 445 raise ValueError(f'Invalid test_mode input {self.test_mode} {type(self.test_mode)}') |
452 if not isinstance(num_core, int) or num_core < -1 or num_core == 0: | 446 if not isinstance(num_core, int) or num_core < -1 or num_core == 0: |
453 raise ValueError(f'Invalid num_core input {num_core} {type(num_core)}') | 447 raise ValueError(f'Invalid num_core input {num_core} {type(num_core)}') |
454 if num_core == -1: | 448 if num_core == -1: |
455 self.num_core = mp.cpu_count() | 449 self.num_core = mp.cpu_count() |
456 else: | 450 else: |
663 | 657 |
664 # Take median | 658 # Take median |
665 self.tdf = np.median(tdf_stack, axis=0) | 659 self.tdf = np.median(tdf_stack, axis=0) |
666 del tdf_stack | 660 del tdf_stack |
667 | 661 |
668 # RV make input of some kind (not always needed) | 662 # Remove dark field intensities above the cutoff |
669 tdf_cutoff = 21 | 663 tdf_cutoff = dark_field.get('cutoff') |
670 self.tdf[self.tdf > tdf_cutoff] = np.nan | 664 if tdf_cutoff is not None: |
665 if not is_num(tdf_cutoff, 0): | |
666 logging.warning(f'Ignoring illegal value of tdf_cutoff {tdf_cutoff}') | |
667 else: | |
668 self.tdf[self.tdf > tdf_cutoff] = np.nan | |
669 logging.debug(f'tdf_cutoff = {tdf_cutoff}') | |
670 | |
671 tdf_mean = np.nanmean(self.tdf) | 671 tdf_mean = np.nanmean(self.tdf) |
672 logging.debug(f'tdf_cutoff = {tdf_cutoff}') | |
673 logging.debug(f'tdf_mean = {tdf_mean}') | 672 logging.debug(f'tdf_mean = {tdf_mean}') |
674 np.nan_to_num(self.tdf, copy=False, nan=tdf_mean, posinf=tdf_mean, neginf=0.) | 673 np.nan_to_num(self.tdf, copy=False, nan=tdf_mean, posinf=tdf_mean, neginf=0.) |
675 if self.galaxy_flag: | 674 if self.galaxy_flag: |
676 quickImshow(self.tdf, title='dark field', path='setup_pngs', | 675 quickImshow(self.tdf, title='dark field', path='setup_pngs', |
677 save_fig=True, save_only=True) | 676 save_fig=True, save_only=True) |
1240 t0 = time() | 1239 t0 = time() |
1241 recon_sinogram = iradon(sinogram, theta=thetas_deg, circle=True) | 1240 recon_sinogram = iradon(sinogram, theta=thetas_deg, circle=True) |
1242 logging.debug(f'inverting sinogram took {time()-t0:.2f} seconds!') | 1241 logging.debug(f'inverting sinogram took {time()-t0:.2f} seconds!') |
1243 del sinogram | 1242 del sinogram |
1244 | 1243 |
1245 # Removing ring artifacts | 1244 # Performing Gaussian filtering and removing ring artifacts |
1246 # RV parameters for the denoise, gaussian, and ring removal will be different for different feature sizes | 1245 recon_parameters = self.config.get('recon_parameters') |
1246 if recon_parameters is None: | |
1247 sigma = 1.0 | |
1248 ring_width = 15 | |
1249 else: | |
1250 sigma = recon_parameters.get('gaussian_sigma', 1.0) | |
1251 if not is_num(sigma, 0.0): | |
1252 logging.warning(f'Illegal gaussian_sigma ({sigma}) in _reconstructOnePlane, '+ | |
1253 'set to a default value of 1.0') | |
1254 sigma = 1.0 | |
1255 ring_width = recon_parameters.get('ring_width', 15) | |
1256 if not is_int(ring_width, 0): | |
1257 logging.warning(f'Illegal ring_width ({ring_width}) in _reconstructOnePlane, '+ | |
1258 'set to a default value of 15') | |
1259 ring_width = 15 | |
1247 t0 = time() | 1260 t0 = time() |
1248 # recon_sinogram = filters.gaussian(recon_sinogram, 3.0) | 1261 recon_sinogram = spi.gaussian_filter(recon_sinogram, sigma, mode='nearest') |
1249 recon_sinogram = spi.gaussian_filter(recon_sinogram, 0.5) | |
1250 recon_clean = np.expand_dims(recon_sinogram, axis=0) | 1262 recon_clean = np.expand_dims(recon_sinogram, axis=0) |
1251 del recon_sinogram | 1263 del recon_sinogram |
1252 t1 = time() | 1264 t1 = time() |
1253 logging.debug(f'running remove_ring on {num_core} cores ...') | 1265 logging.debug(f'running remove_ring on {num_core} cores ...') |
1254 recon_clean = tomopy.misc.corr.remove_ring(recon_clean, rwidth=17, ncore=num_core) | 1266 recon_clean = tomopy.misc.corr.remove_ring(recon_clean, rwidth=ring_width, ncore=num_core) |
1255 logging.debug(f'... remove_ring took {time()-t1:.2f} seconds!') | 1267 logging.debug(f'... remove_ring took {time()-t1:.2f} seconds!') |
1256 logging.debug(f'filtering and removing ring artifact took {time()-t0:.2f} seconds!') | 1268 logging.debug(f'filtering and removing ring artifact took {time()-t0:.2f} seconds!') |
1257 return recon_clean | 1269 return recon_clean |
1258 | 1270 |
1259 def _plotEdgesOnePlane(self, recon_plane, title, path=None, weight=0.001): | 1271 def _plotEdgesOnePlane(self, recon_plane, title, path=None): |
1260 # RV parameters for the denoise, gaussian, and ring removal will be different for different feature sizes | 1272 vis_parameters = self.config.get('vis_parameters') |
1261 edges = denoise_tv_chambolle(recon_plane, weight = weight) | 1273 if vis_parameters is None: |
1274 weight = 0.1 | |
1275 else: | |
1276 weight = vis_parameters.get('denoise_weight', 0.1) | |
1277 if not is_num(weight, 0.0): | |
1278 logging.warning(f'Illegal weight ({weight}) in _plotEdgesOnePlane, '+ | |
1279 'set to a default value of 0.1') | |
1280 weight = 0.1 | |
1281 edges = denoise_tv_chambolle(recon_plane, weight=weight) | |
1262 vmax = np.max(edges[0,:,:]) | 1282 vmax = np.max(edges[0,:,:]) |
1263 vmin = -vmax | 1283 vmin = -vmax |
1264 if self.galaxy_flag: | 1284 if self.galaxy_flag: |
1265 quickImshow(edges[0,:,:], title, path=path, save_fig=True, save_only=True, | 1285 quickImshow(edges[0,:,:], title, path=path, save_fig=True, save_only=True, |
1266 cmap='gray', vmin=vmin, vmax=vmax) | 1286 cmap='gray', vmin=vmin, vmax=vmax) |
1393 center_offset = center_offset_vo | 1413 center_offset = center_offset_vo |
1394 else: | 1414 else: |
1395 center_offset = input_num(' Enter chosen center offset', -center, center) | 1415 center_offset = input_num(' Enter chosen center offset', -center, center) |
1396 return float(center_offset) | 1416 return float(center_offset) |
1397 | 1417 |
1398 def _reconstructOneTomoStack(self, tomo_stack, thetas, row_bounds=None, | 1418 def _reconstructOneTomoStack(self, tomo_stack, thetas, row_bounds=None, center_offsets=[], |
1399 center_offsets=[], sigma=0.1, rwidth=30, num_core=1, algorithm='gridrec', | 1419 num_core=1, algorithm='gridrec'): |
1400 run_secondary_sirt=False, secondary_iter=100): | |
1401 """reconstruct a single tomography stack. | 1420 """reconstruct a single tomography stack. |
1402 """ | 1421 """ |
1403 # stack order: row,theta,column | 1422 # stack order: row,theta,column |
1404 # thetas must be in radians | 1423 # thetas must be in radians |
1405 # centers_offset: tomography axis shift in pixels relative to column center | 1424 # centers_offset: tomography axis shift in pixels relative to column center |
1423 else: | 1442 else: |
1424 if center_offsets.size != row_bounds[1]-row_bounds[0]: | 1443 if center_offsets.size != row_bounds[1]-row_bounds[0]: |
1425 raise ValueError('center_offsets dimension mismatch in reconstructOneTomoStack') | 1444 raise ValueError('center_offsets dimension mismatch in reconstructOneTomoStack') |
1426 centers = center_offsets | 1445 centers = center_offsets |
1427 centers += tomo_stack.shape[2]/2 | 1446 centers += tomo_stack.shape[2]/2 |
1447 | |
1448 # Removing horizontal stripe and ring artifacts and perform secondary iterations | |
1449 recon_parameters = self.config.get('recon_parameters') | |
1450 if recon_parameters is None: | |
1451 sigma = 2.0 | |
1452 secondary_iters = 0 | |
1453 ring_width = 15 | |
1454 else: | |
1455 sigma = recon_parameters.get('stripe_fw_sigma', 2.0) | |
1456 if not is_num(sigma, 0): | |
1457 logging.warning(f'Illegal stripe_fw_sigma ({sigma}) in '+ | |
1458 '_reconstructOneTomoStack, set to a default value of 2.0') | |
1459 ring_width = 15 | |
1460 secondary_iters = recon_parameters.get('secondary_iters', 0) | |
1461 if not is_int(secondary_iters, 0): | |
1462 logging.warning(f'Illegal secondary_iters ({secondary_iters}) in '+ | |
1463 '_reconstructOneTomoStack, set to a default value of 0 (skip them)') | |
1464 ring_width = 0 | |
1465 ring_width = recon_parameters.get('ring_width', 15) | |
1466 if not is_int(ring_width, 0): | |
1467 logging.warning(f'Illegal ring_width ({ring_width}) in _reconstructOnePlane, '+ | |
1468 'set to a default value of 15') | |
1469 ring_width = 15 | |
1428 if True: | 1470 if True: |
1429 t0 = time() | 1471 t0 = time() |
1430 if num_core > num_core_tomopy_limit: | 1472 if num_core > num_core_tomopy_limit: |
1431 logging.debug('running remove_stripe_fw on {num_core_tomopy_limit} cores ...') | 1473 logging.debug('running remove_stripe_fw on {num_core_tomopy_limit} cores ...') |
1432 tomo_stack = tomopy.prep.stripe.remove_stripe_fw( | 1474 tomo_stack = tomopy.prep.stripe.remove_stripe_fw( |
1443 t0 = time() | 1485 t0 = time() |
1444 logging.debug(f'running recon on {num_core} cores ...') | 1486 logging.debug(f'running recon on {num_core} cores ...') |
1445 tomo_recon_stack = tomopy.recon(tomo_stack, thetas, centers, sinogram_order=True, | 1487 tomo_recon_stack = tomopy.recon(tomo_stack, thetas, centers, sinogram_order=True, |
1446 algorithm=algorithm, ncore=num_core) | 1488 algorithm=algorithm, ncore=num_core) |
1447 logging.debug(f'... recon took {time()-t0:.2f} seconds!') | 1489 logging.debug(f'... recon took {time()-t0:.2f} seconds!') |
1448 if run_secondary_sirt and secondary_iter > 0: | 1490 if secondary_iters > 0: |
1449 logging.debug(f'running {secondary_iter} secondary iterations') | 1491 logging.debug(f'running {secondary_iters} secondary iterations') |
1450 #options = {'method':'SIRT_CUDA', 'proj_type':'cuda', 'num_iter':secondary_iter} | 1492 #options = {'method':'SIRT_CUDA', 'proj_type':'cuda', 'num_iter':secondary_iters} |
1451 #RV: doesn't work for me: "Error: CUDA error 803: system has unsupported display driver / | 1493 #RV: doesn't work for me: "Error: CUDA error 803: system has unsupported display driver / |
1452 # cuda driver combination." | 1494 # cuda driver combination." |
1453 #options = {'method':'SIRT', 'proj_type':'linear', 'MinConstraint': 0, 'num_iter':secondary_iter} | 1495 #options = {'method':'SIRT', 'proj_type':'linear', 'MinConstraint': 0, 'num_iter':secondary_iters} |
1454 #SIRT did not finish while running overnight | 1496 #SIRT did not finish while running overnight |
1455 #options = {'method':'SART', 'proj_type':'linear', 'num_iter':secondary_iter} | 1497 #options = {'method':'SART', 'proj_type':'linear', 'num_iter':secondary_iters} |
1456 options = {'method':'SART', 'proj_type':'linear', 'MinConstraint': 0, | 1498 options = {'method':'SART', 'proj_type':'linear', 'MinConstraint': 0, |
1457 'num_iter':secondary_iter} | 1499 'num_iter':secondary_iters} |
1458 t0 = time() | 1500 t0 = time() |
1459 logging.debug(f'running recon on {num_core} cores ...') | 1501 logging.debug(f'running recon on {num_core} cores ...') |
1460 tomo_recon_stack = tomopy.recon(tomo_stack, thetas, centers, | 1502 tomo_recon_stack = tomopy.recon(tomo_stack, thetas, centers, |
1461 init_recon=tomo_recon_stack, options=options, sinogram_order=True, | 1503 init_recon=tomo_recon_stack, options=options, sinogram_order=True, |
1462 algorithm=tomopy.astra, ncore=num_core) | 1504 algorithm=tomopy.astra, ncore=num_core) |
1463 logging.debug(f'... recon took {time()-t0:.2f} seconds!') | 1505 logging.debug(f'... recon took {time()-t0:.2f} seconds!') |
1464 if True: | 1506 if True: |
1465 t0 = time() | 1507 t0 = time() |
1466 logging.debug(f'running remove_ring on {num_core} cores ...') | 1508 logging.debug(f'running remove_ring on {num_core} cores ...') |
1467 tomopy.misc.corr.remove_ring(tomo_recon_stack, rwidth=rwidth, out=tomo_recon_stack, | 1509 tomopy.misc.corr.remove_ring(tomo_recon_stack, rwidth=ring_width, out=tomo_recon_stack, |
1468 ncore=num_core) | 1510 ncore=num_core) |
1469 logging.debug(f'... remove_ring took {time()-t0:.2f} seconds!') | 1511 logging.debug(f'... remove_ring took {time()-t0:.2f} seconds!') |
1470 return tomo_recon_stack | 1512 return tomo_recon_stack |
1471 | 1513 |
1472 def findImageFiles(self, tiff_to_h5_flag = False): | 1514 def findImageFiles(self, tiff_to_h5_flag = False): |
1621 logging.warning('Ignoring galaxy_param in genTomoStacks (only for Galaxy)') | 1663 logging.warning('Ignoring galaxy_param in genTomoStacks (only for Galaxy)') |
1622 galaxy_param = None | 1664 galaxy_param = None |
1623 tdf_files, tbf_files, tomo_stack_files = self.findImageFiles() | 1665 tdf_files, tbf_files, tomo_stack_files = self.findImageFiles() |
1624 if not self.is_valid: | 1666 if not self.is_valid: |
1625 return | 1667 return |
1668 if self.test_mode: | |
1669 required = True | |
1670 else: | |
1671 required = False | |
1626 for i,stack in enumerate(stacks): | 1672 for i,stack in enumerate(stacks): |
1627 if not self.tomo_stacks[i].size and stack.get('preprocessed', False): | 1673 if not self.tomo_stacks[i].size and stack.get('preprocessed', False): |
1628 self.tomo_stacks[i], available_stacks[i] = \ | 1674 self.tomo_stacks[i], available_stacks[i] = \ |
1629 self._loadTomo('red stack', stack['index']) | 1675 self._loadTomo('red stack', stack['index'], required=required) |
1630 | 1676 |
1631 # Preprocess any unloaded stacks | 1677 # Preprocess any unloaded stacks |
1632 if False in available_stacks: | 1678 if False in available_stacks: |
1633 logging.debug('Preprocessing tomography images') | 1679 logging.debug('Preprocessing tomography images') |
1634 | 1680 |
1926 if self.save_plots_only: | 1972 if self.save_plots_only: |
1927 clearImshow(f'theta={theta_start}') | 1973 clearImshow(f'theta={theta_start}') |
1928 if use_row: | 1974 if use_row: |
1929 center_offset = find_center.get('upper_center_offset') | 1975 center_offset = find_center.get('upper_center_offset') |
1930 if is_num(center_offset): | 1976 if is_num(center_offset): |
1931 use_center = input_yesrnNo('Current upper center offset = '+ | 1977 use_center = input_yesno('Current upper center offset = '+ |
1932 f'{center_offset}, use this value (y/n)?', 'y') | 1978 f'{center_offset}, use this value (y/n)?', 'y') |
1933 if not use_center: | 1979 if not use_center: |
1934 if not use_row: | 1980 if not use_row: |
1935 if not self.test_mode: | 1981 if not self.test_mode: |
1936 quickImshow(center_stack[:,0,:], title=f'theta={theta_start}', | 1982 quickImshow(center_stack[:,0,:], title=f'theta={theta_start}', |
2126 center_offsets = [lower_center_offset-lower_row*center_slope, | 2172 center_offsets = [lower_center_offset-lower_row*center_slope, |
2127 upper_center_offset+(self.tomo_stacks[i].shape[0]-1-upper_row)*center_slope] | 2173 upper_center_offset+(self.tomo_stacks[i].shape[0]-1-upper_row)*center_slope] |
2128 t0 = time() | 2174 t0 = time() |
2129 logging.debug(f'running _reconstructOneTomoStack on {num_core} cores ...') | 2175 logging.debug(f'running _reconstructOneTomoStack on {num_core} cores ...') |
2130 self.tomo_recon_stacks[i]= self._reconstructOneTomoStack(self.tomo_stacks[i], | 2176 self.tomo_recon_stacks[i]= self._reconstructOneTomoStack(self.tomo_stacks[i], |
2131 thetas, center_offsets=center_offsets, sigma=0.1, num_core=num_core, | 2177 thetas, center_offsets=center_offsets, num_core=num_core, |
2132 algorithm='gridrec', run_secondary_sirt=True, secondary_iter=25) | 2178 algorithm='gridrec') |
2133 logging.debug(f'... _reconstructOneTomoStack took {time()-t0:.2f} seconds!') | 2179 logging.debug(f'... _reconstructOneTomoStack took {time()-t0:.2f} seconds!') |
2134 logging.info(f'Reconstruction of stack {index} took {time()-t0:.2f} seconds!') | 2180 logging.info(f'Reconstruction of stack {index} took {time()-t0:.2f} seconds!') |
2135 if self.galaxy_flag: | 2181 if self.galaxy_flag: |
2136 x_slice = int(self.tomo_stacks[i].shape[0]/2) | 2182 x_slice = int(self.tomo_recon_stacks[i].shape[0]/2) |
2137 title = f'{basetitle} {index} xslice{x_slice}' | 2183 title = f'{basetitle} {index} xslice{x_slice}' |
2138 quickImshow(self.tomo_recon_stacks[i][x_slice,:,:], title=title, | 2184 quickImshow(self.tomo_recon_stacks[i][x_slice,:,:], title=title, |
2139 path='center_slice_pngs', save_fig=True, save_only=True) | 2185 path='center_slice_pngs', save_fig=True, save_only=True) |
2140 y_slice = int(self.tomo_stacks[i].shape[0]/2) | 2186 y_slice = int(self.tomo_recon_stacks[i].shape[1]/2) |
2141 title = f'{basetitle} {index} yslice{y_slice}' | 2187 title = f'{basetitle} {index} yslice{y_slice}' |
2142 quickImshow(self.tomo_recon_stacks[i][:,y_slice,:], title=title, | 2188 quickImshow(self.tomo_recon_stacks[i][:,y_slice,:], title=title, |
2143 path='center_slice_pngs', save_fig=True, save_only=True) | 2189 path='center_slice_pngs', save_fig=True, save_only=True) |
2144 z_slice = int(self.tomo_stacks[i].shape[0]/2) | 2190 z_slice = int(self.tomo_recon_stacks[i].shape[2]/2) |
2145 title = f'{basetitle} {index} zslice{z_slice}' | 2191 title = f'{basetitle} {index} zslice{z_slice}' |
2146 quickImshow(self.tomo_recon_stacks[i][:,:,z_slice], title=title, | 2192 quickImshow(self.tomo_recon_stacks[i][:,:,z_slice], title=title, |
2147 path='center_slice_pngs', save_fig=True, save_only=True) | 2193 path='center_slice_pngs', save_fig=True, save_only=True) |
2148 elif not self.test_mode: | 2194 else: |
2149 x_slice = int(self.tomo_stacks[i].shape[0]/2) | 2195 x_slice = int(self.tomo_recon_stacks[i].shape[0]/2) |
2150 title = f'{basetitle} {index} xslice{x_slice}' | 2196 title = f'{basetitle} {index} xslice{x_slice}' |
2151 quickImshow(self.tomo_recon_stacks[i][x_slice,:,:], title=title, | 2197 quickImshow(self.tomo_recon_stacks[i][x_slice,:,:], title=title, |
2152 path=self.output_folder, save_fig=self.save_plots, | 2198 path=self.output_folder, save_fig=self.save_plots, |
2153 save_only=self.save_plots_only) | 2199 save_only=self.save_plots_only) |
2154 quickPlot(self.tomo_recon_stacks[i] | 2200 y_slice = int(self.tomo_recon_stacks[i].shape[1]/2) |
2155 [x_slice,int(self.tomo_recon_stacks[i].shape[2]/2),:], | 2201 title = f'{basetitle} {index} yslice{y_slice}' |
2156 title=f'{title} cut{int(self.tomo_recon_stacks[i].shape[2]/2)}', | 2202 quickImshow(self.tomo_recon_stacks[i][:,y_slice,:], title=title, |
2157 path=self.output_folder, save_fig=self.save_plots, | 2203 path=self.output_folder, save_fig=self.save_plots, |
2158 save_only=self.save_plots_only) | 2204 save_only=self.save_plots_only) |
2159 self._saveTomo('recon stack', self.tomo_recon_stacks[i], index) | 2205 z_slice = int(self.tomo_recon_stacks[i].shape[2]/2) |
2206 title = f'{basetitle} {index} zslice{z_slice}' | |
2207 quickImshow(self.tomo_recon_stacks[i][:,:,z_slice], title=title, | |
2208 path=self.output_folder, save_fig=self.save_plots, | |
2209 save_only=self.save_plots_only) | |
2210 # quickPlot(self.tomo_recon_stacks[i] | |
2211 # [x_slice,int(self.tomo_recon_stacks[i].shape[1]/2),:], | |
2212 # title=f'{title} cut{int(self.tomo_recon_stacks[i].shape[1]/2)}', | |
2213 # path=self.output_folder, save_fig=self.save_plots, | |
2214 # save_only=self.save_plots_only) | |
2215 if not self.test_mode: | |
2216 self._saveTomo('recon stack', self.tomo_recon_stacks[i], index) | |
2160 self.tomo_stacks[i] = np.array([]) | 2217 self.tomo_stacks[i] = np.array([]) |
2161 | 2218 |
2162 # Update config and save to file | 2219 # Update config and save to file |
2163 stack['reconstructed'] = True | 2220 stack['reconstructed'] = True |
2164 combine_stacks = self.config.get('combine_stacks') | 2221 combine_stacks = self.config.get('combine_stacks') |
2279 quickPlot((range(tomosum.size), tomosum), | 2336 quickPlot((range(tomosum.size), tomosum), |
2280 ([x_bounds[0], x_bounds[0]], [tomosum_min, tomosum_max], 'r-'), | 2337 ([x_bounds[0], x_bounds[0]], [tomosum_min, tomosum_max], 'r-'), |
2281 ([x_bounds[1]-1, x_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), | 2338 ([x_bounds[1]-1, x_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), |
2282 title=f'recon stack sum yz', path='combine_pngs', save_fig=True, save_only=True) | 2339 title=f'recon stack sum yz', path='combine_pngs', save_fig=True, save_only=True) |
2283 else: | 2340 else: |
2341 x_bounds = None | |
2342 change_x_bounds = 'y' | |
2284 if combine_stacks and 'x_bounds' in combine_stacks: | 2343 if combine_stacks and 'x_bounds' in combine_stacks: |
2285 x_bounds = combine_stacks['x_bounds'] | 2344 x_bounds = combine_stacks['x_bounds'] |
2286 if not is_index_range(x_bounds, 0, tomosum.size): | 2345 if is_index_range(x_bounds, 0, tomosum.size): |
2346 if not self.test_mode: | |
2347 quickPlot(tomosum, vlines=x_bounds, title='recon stack sum yz') | |
2348 print(f'x_bounds = {x_bounds} (lower bound inclusive, upper bound '+ | |
2349 'exclusive)') | |
2350 change_x_bounds = 'n' | |
2351 else: | |
2287 illegal_value(x_bounds, 'combine_stacks:x_bounds', 'config file') | 2352 illegal_value(x_bounds, 'combine_stacks:x_bounds', 'config file') |
2288 elif not self.test_mode: | 2353 x_bounds = None |
2354 if self.test_mode: | |
2355 if x_bounds is None: | |
2356 x_bounds = [0, tomosum.size] | |
2357 else: | |
2358 if not input_yesno('\nDo you want to change the image x-bounds (y/n)?', | |
2359 change_x_bounds): | |
2360 if x_bounds is None: | |
2361 x_bounds = [0, tomosum.size] | |
2362 else: | |
2289 accept = False | 2363 accept = False |
2364 if x_bounds is None: | |
2365 index_ranges = None | |
2366 else: | |
2367 index_ranges = [x_bounds] | |
2290 while not accept: | 2368 while not accept: |
2291 mask, x_bounds = draw_mask_1d(tomosum, current_index_ranges=x_bounds, | 2369 mask, x_bounds = draw_mask_1d(tomosum, current_index_ranges=index_ranges, |
2292 title='select x data range', legend='recon stack sum yz') | 2370 title='select x data range', legend='recon stack sum yz') |
2293 while len(x_bounds) != 1: | 2371 while len(x_bounds) != 1: |
2294 print('Please select exactly one continuous range') | 2372 print('Please select exactly one continuous range') |
2295 mask, x_bounds = draw_mask_1d(tomosum, title='select x data range', | 2373 mask, x_bounds = draw_mask_1d(tomosum, title='select x data range', |
2296 legend='recon stack sum yz') | 2374 legend='recon stack sum yz') |
2297 x_bounds = list(x_bounds[0]) | 2375 x_bounds = list(x_bounds[0]) |
2298 quickPlot(tomosum, vlines=x_bounds, title='recon stack sum yz') | 2376 quickPlot(tomosum, vlines=x_bounds, title='recon stack sum yz') |
2299 print(f'x_bounds = {x_bounds} (lower bound inclusive, upper bound '+ | 2377 print(f'x_bounds = {x_bounds} (lower bound inclusive, upper bound '+ |
2300 'exclusive)') | 2378 'exclusive)') |
2301 accept = input_yesno('Accept these bounds (y/n)?', 'y') | 2379 accept = input_yesno('Accept these bounds (y/n)?', 'y') |
2302 if not accept: | |
2303 x_bounds = None | |
2304 else: | |
2305 if not input_yesno('\nDo you want to change the image x-bounds (y/n)?', 'n'): | |
2306 x_bounds = [0, tomosum.size] | |
2307 else: | |
2308 accept = False | |
2309 while not accept: | |
2310 mask, x_bounds = draw_mask_1d(tomosum, title='select x data range', | |
2311 legend='recon stack sum yz') | |
2312 while len(x_bounds) != 1: | |
2313 print('Please select exactly one continuous range') | |
2314 mask, x_bounds = draw_mask_1d(tomosum, title='select x data range', | |
2315 legend='recon stack sum yz') | |
2316 x_bounds = list(x_bounds[0]) | |
2317 quickPlot(tomosum, vlines=x_bounds, title='recon stack sum yz') | |
2318 print(f'x_bounds = {x_bounds} (lower bound inclusive, upper bound '+ | |
2319 'exclusive)') | |
2320 accept = input_yesno('Accept these bounds (y/n)?', 'y') | |
2321 if False and self.test_mode: | |
2322 np.savetxt(f'{self.output_folder}/recon_stack_sum_yz.txt', | |
2323 tomosum[x_bounds[0]:x_bounds[1]], fmt='%.6e') | |
2324 if self.save_plots_only: | 2380 if self.save_plots_only: |
2325 clearPlot('recon stack sum yz') | 2381 clearPlot('recon stack sum yz') |
2382 logging.info(f'x_bounds = {x_bounds}') | |
2326 | 2383 |
2327 # Selecting y bounds (in xz-plane) | 2384 # Selecting y bounds (in xz-plane) |
2328 tomosum = 0 | 2385 tomosum = 0 |
2329 #RV FIX := | 2386 #RV FIX := |
2330 [tomosum := tomosum+np.sum(tomo_recon_stack, axis=(0,1)) for tomo_recon_stack in | 2387 [tomosum := tomosum+np.sum(tomo_recon_stack, axis=(0,1)) for tomo_recon_stack in |
2341 quickPlot((range(tomosum.size), tomosum), | 2398 quickPlot((range(tomosum.size), tomosum), |
2342 ([y_bounds[0], y_bounds[0]], [tomosum_min, tomosum_max], 'r-'), | 2399 ([y_bounds[0], y_bounds[0]], [tomosum_min, tomosum_max], 'r-'), |
2343 ([y_bounds[1]-1, y_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), | 2400 ([y_bounds[1]-1, y_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), |
2344 title=f'recon stack sum xz', path='combine_pngs', save_fig=True, save_only=True) | 2401 title=f'recon stack sum xz', path='combine_pngs', save_fig=True, save_only=True) |
2345 else: | 2402 else: |
2403 y_bounds = None | |
2404 change_y_bounds = 'y' | |
2346 if combine_stacks and 'y_bounds' in combine_stacks: | 2405 if combine_stacks and 'y_bounds' in combine_stacks: |
2347 y_bounds = combine_stacks['y_bounds'] | 2406 y_bounds = combine_stacks['y_bounds'] |
2348 if not is_index_range(y_bounds, 0, tomosum.size): | 2407 if is_index_range(y_bounds, 0, tomosum.size): |
2408 if not self.test_mode: | |
2409 quickPlot(tomosum, vlines=y_bounds, title='recon stack sum xz') | |
2410 print(f'y_bounds = {y_bounds} (lower bound inclusive, upper bound '+ | |
2411 'exclusive)') | |
2412 change_y_bounds = 'n' | |
2413 else: | |
2349 illegal_value(y_bounds, 'combine_stacks:y_bounds', 'config file') | 2414 illegal_value(y_bounds, 'combine_stacks:y_bounds', 'config file') |
2350 elif not self.test_mode: | 2415 y_bounds = None |
2416 if self.test_mode: | |
2417 if y_bounds is None: | |
2418 y_bounds = [0, tomosum.size] | |
2419 else: | |
2420 if not input_yesno('\nDo you want to change the image y-bounds (y/n)?', | |
2421 change_y_bounds): | |
2422 if y_bounds is None: | |
2423 y_bounds = [0, tomosum.size] | |
2424 else: | |
2351 accept = False | 2425 accept = False |
2426 if y_bounds is None: | |
2427 index_ranges = None | |
2428 else: | |
2429 index_ranges = [y_bounds] | |
2352 while not accept: | 2430 while not accept: |
2353 mask, y_bounds = draw_mask_1d(tomosum, current_index_ranges=y_bounds, | 2431 mask, y_bounds = draw_mask_1d(tomosum, current_index_ranges=index_ranges, |
2354 title='select y data range', legend='recon stack sum xz') | 2432 title='select x data range', legend='recon stack sum xz') |
2355 while len(y_bounds) != 1: | 2433 while len(y_bounds) != 1: |
2356 print('Please select exactly one continuous range') | 2434 print('Please select exactly one continuous range') |
2357 mask, y_bounds = draw_mask_1d(tomosum, title='select y data range', | 2435 mask, y_bounds = draw_mask_1d(tomosum, title='select x data range', |
2358 legend='recon stack sum xz') | 2436 legend='recon stack sum xz') |
2359 y_bounds = list(y_bounds[0]) | 2437 y_bounds = list(y_bounds[0]) |
2360 quickPlot(tomosum, vlines=y_bounds, title='recon stack sum xz') | 2438 quickPlot(tomosum, vlines=y_bounds, title='recon stack sum xz') |
2361 print(f'y_bounds = {y_bounds} (lower bound inclusive, upper bound '+ | 2439 print(f'y_bounds = {y_bounds} (lower bound inclusive, upper bound '+ |
2362 'exclusive)') | 2440 'exclusive)') |
2363 accept = input_yesno('Accept these bounds (y/n)?', 'y') | 2441 accept = input_yesno('Accept these bounds (y/n)?', 'y') |
2364 if not accept: | |
2365 y_bounds = None | |
2366 else: | |
2367 if not input_yesno('\nDo you want to change the image y-bounds (y/n)?', 'n'): | |
2368 y_bounds = [0, tomosum.size] | |
2369 else: | |
2370 accept = False | |
2371 while not accept: | |
2372 mask, y_bounds = draw_mask_1d(tomosum, title='select y data range', | |
2373 legend='recon stack sum xz') | |
2374 while len(y_bounds) != 1: | |
2375 print('Please select exactly one continuous range') | |
2376 mask, y_bounds = draw_mask_1d(tomosum, title='select y data range', | |
2377 legend='recon stack sum xz') | |
2378 y_bounds = list(y_bounds[0]) | |
2379 quickPlot(tomosum, vlines=y_bounds, title='recon stack sum xz') | |
2380 print(f'y_bounds = {y_bounds} (lower bound inclusive, upper bound '+ | |
2381 'exclusive)') | |
2382 accept = input_yesno('Accept these bounds (y/n)?', 'y') | |
2383 if False and self.test_mode: | |
2384 np.savetxt(f'{self.output_folder}/recon_stack_sum_xz.txt', | |
2385 tomosum[y_bounds[0]:y_bounds[1]], fmt='%.6e') | |
2386 if self.save_plots_only: | 2442 if self.save_plots_only: |
2387 clearPlot('recon stack sum xz') | 2443 clearPlot('recon stack sum xz') |
2444 logging.info(f'y_bounds = {y_bounds}') | |
2388 | 2445 |
2389 # Combine reconstructed tomography stacks | 2446 # Combine reconstructed tomography stacks |
2390 logging.info(f'Combining reconstructed stacks ...') | 2447 logging.info(f'Combining reconstructed stacks ...') |
2391 t0 = time() | 2448 t0 = time() |
2392 num_tomo_stacks = len(stacks) | 2449 num_tomo_stacks = len(stacks) |
2406 [self.tomo_recon_stacks[num_tomo_stacks-1][row_bounds[0]:, | 2463 [self.tomo_recon_stacks[num_tomo_stacks-1][row_bounds[0]:, |
2407 x_bounds[0]:x_bounds[1],y_bounds[0]:y_bounds[1]]]) | 2464 x_bounds[0]:x_bounds[1],y_bounds[0]:y_bounds[1]]]) |
2408 logging.info(f'... done in {time()-t0:.2f} seconds!') | 2465 logging.info(f'... done in {time()-t0:.2f} seconds!') |
2409 combined_stacks = [stack['index'] for stack in stacks] | 2466 combined_stacks = [stack['index'] for stack in stacks] |
2410 | 2467 |
2411 # Wrap up if in test_mode | 2468 # Selecting z bounds (in xy-plane) |
2412 tomosum = np.sum(tomo_recon_combined, axis=(1,2)) | 2469 tomosum = np.sum(tomo_recon_combined, axis=(1,2)) |
2413 if self.test_mode: | |
2414 zoom_perc = self.config['preprocess'].get('zoom_perc', 100) | |
2415 filename = 'recon combined sum xy' | |
2416 if zoom_perc is None or zoom_perc == 100: | |
2417 filename += ' fullres.dat' | |
2418 else: | |
2419 filename += f' {zoom_perc}p.dat' | |
2420 quickPlot(tomosum, title='recon combined sum xy', | |
2421 path=self.output_folder, save_fig=self.save_plots, | |
2422 save_only=self.save_plots_only) | |
2423 if False: | |
2424 np.savetxt(f'{self.output_folder}/recon_combined_sum_xy.txt', | |
2425 tomosum, fmt='%.6e') | |
2426 np.savetxt(f'{self.output_folder}/recon_combined.txt', | |
2427 tomo_recon_combined[int(tomosum.size/2),:,:], fmt='%.6e') | |
2428 | |
2429 # Update config and save to file | |
2430 if combine_stacks: | |
2431 combine_stacks['x_bounds'] = x_bounds | |
2432 combine_stacks['y_bounds'] = y_bounds | |
2433 combine_stacks['stacks'] = combined_stacks | |
2434 else: | |
2435 self.config['combine_stacks'] = {'x_bounds' : x_bounds, 'y_bounds' : y_bounds, | |
2436 'stacks' : combined_stacks} | |
2437 self.cf.saveFile(self.config_out) | |
2438 return | |
2439 | |
2440 # Selecting z bounds (in xy-plane) | |
2441 if self.galaxy_flag: | 2470 if self.galaxy_flag: |
2442 if z_bounds[0] == -1: | 2471 if z_bounds[0] == -1: |
2443 z_bounds[0] = 0 | 2472 z_bounds[0] = 0 |
2444 if z_bounds[1] == -1: | 2473 if z_bounds[1] == -1: |
2445 z_bounds[1] = tomosum.size | 2474 z_bounds[1] = tomosum.size |
2450 quickPlot((range(tomosum.size), tomosum), | 2479 quickPlot((range(tomosum.size), tomosum), |
2451 ([z_bounds[0], z_bounds[0]], [tomosum_min, tomosum_max], 'r-'), | 2480 ([z_bounds[0], z_bounds[0]], [tomosum_min, tomosum_max], 'r-'), |
2452 ([z_bounds[1]-1, z_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), | 2481 ([z_bounds[1]-1, z_bounds[1]-1], [tomosum_min, tomosum_max], 'r-'), |
2453 title=f'recon stack sum xy', path='combine_pngs', save_fig=True, save_only=True) | 2482 title=f'recon stack sum xy', path='combine_pngs', save_fig=True, save_only=True) |
2454 else: | 2483 else: |
2455 if not input_yesno('\nDo you want to change the image z-bounds (y/n)?', 'n'): | 2484 z_bounds = None |
2456 z_bounds = [0, tomosum.size] | 2485 if combine_stacks and 'z_bounds' in combine_stacks: |
2457 else: | 2486 z_bounds = combine_stacks['z_bounds'] |
2458 accept = False | 2487 if is_index_range(z_bounds, 0, tomosum.size): |
2459 while not accept: | 2488 if not self.test_mode: |
2460 mask, z_bounds = draw_mask_1d(tomosum, title='select z data range', | 2489 quickPlot(tomosum, vlines=z_bounds, title='recon stack sum xy') |
2461 legend='recon stack sum xy') | 2490 print(f'z_bounds = {z_bounds} (lower bound inclusive, upper bound '+ |
2462 while len(z_bounds) != 1: | 2491 'exclusive)') |
2463 print('Please select exactly one continuous range') | 2492 else: |
2464 mask, z_bounds = draw_mask_1d(tomosum, title='select z data range', | 2493 illegal_value(z_bounds, 'combine_stacks:z_bounds', 'config file') |
2465 legend='recon stack sum xy') | 2494 z_bounds = None |
2466 z_bounds = list(z_bounds[0]) | 2495 if self.test_mode: |
2467 quickPlot(tomosum, vlines=z_bounds, title='recon stack sum xy') | 2496 if z_bounds is None: |
2468 print(f'z_bounds = {z_bounds} (lower bound inclusive, upper bound exclusive)') | 2497 z_bounds = [0, tomosum.size] |
2469 accept = input_yesno('Accept these bounds (y/n)?', 'y') | 2498 else: |
2499 if not input_yesno('\nDo you want to change the image z-bounds (y/n)?', 'n'): | |
2500 if z_bounds is None: | |
2501 z_bounds = [0, tomosum.size] | |
2502 else: | |
2503 accept = False | |
2504 if z_bounds is None: | |
2505 index_ranges = None | |
2506 else: | |
2507 index_ranges = [z_bounds] | |
2508 while not accept: | |
2509 mask, z_bounds = draw_mask_1d(tomosum, current_index_ranges=index_ranges, | |
2510 title='select x data range', legend='recon stack sum xy') | |
2511 while len(z_bounds) != 1: | |
2512 print('Please select exactly one continuous range') | |
2513 mask, z_bounds = draw_mask_1d(tomosum, title='select x data range', | |
2514 legend='recon stack sum xy') | |
2515 z_bounds = list(z_bounds[0]) | |
2516 quickPlot(tomosum, vlines=z_bounds, title='recon stack sum xy') | |
2517 print(f'z_bounds = {z_bounds} (lower bound inclusive, upper bound '+ | |
2518 'exclusive)') | |
2519 accept = input_yesno('Accept these bounds (y/n)?', 'y') | |
2470 if self.save_plots_only: | 2520 if self.save_plots_only: |
2471 clearPlot('recon combined sum xy') | 2521 clearPlot('recon stack sum xy') |
2472 if z_bounds[0] != 0 or z_bounds[1] != tomosum.size: | 2522 logging.info(f'z_bounds = {z_bounds}') |
2473 tomo_recon_combined = tomo_recon_combined[z_bounds[0]:z_bounds[1],:,:] | |
2474 | 2523 |
2475 # Plot center slices | 2524 # Plot center slices |
2476 if self.galaxy_flag: | 2525 if self.galaxy_flag: |
2477 path = 'combine_pngs' | 2526 path = 'combine_pngs' |
2478 save_fig = True | 2527 save_fig = True |
2489 path=path, save_fig=save_fig, save_only=save_only) | 2538 path=path, save_fig=save_fig, save_only=save_only) |
2490 quickImshow(tomo_recon_combined[:,:,int(tomo_recon_combined.shape[2]/2)], | 2539 quickImshow(tomo_recon_combined[:,:,int(tomo_recon_combined.shape[2]/2)], |
2491 title=f'recon combined zslice{int(tomo_recon_combined.shape[2]/2)}', | 2540 title=f'recon combined zslice{int(tomo_recon_combined.shape[2]/2)}', |
2492 path=path, save_fig=save_fig, save_only=save_only) | 2541 path=path, save_fig=save_fig, save_only=save_only) |
2493 | 2542 |
2494 # Save combined reconstructed tomography stack to file | 2543 # Save combined reconstructed tomography stack or test mode data to file |
2495 if self.galaxy_flag: | 2544 if self.galaxy_flag: |
2496 t0 = time() | 2545 t0 = time() |
2497 output_name = galaxy_param['output_name'] | 2546 output_name = galaxy_param['output_name'] |
2498 logging.info(f'Saving combined reconstructed tomography stack to {output_name} ...') | 2547 logging.info(f'Saving combined reconstructed tomography stack to {output_name} ...') |
2499 np.save(output_name, tomo_recon_combined) | 2548 np.save(output_name, tomo_recon_combined) |
2500 logging.info(f'... done in {time()-t0:.2f} seconds!') | 2549 logging.info(f'... done in {time()-t0:.2f} seconds!') |
2550 elif self.test_mode: | |
2551 zoom_perc = self.config['preprocess'].get('zoom_perc', 100) | |
2552 filename = 'recon combined sum xy' | |
2553 if zoom_perc is None or zoom_perc == 100: | |
2554 filename += ' fullres.dat' | |
2555 else: | |
2556 filename += f' {zoom_perc}p.dat' | |
2557 quickPlot(tomosum, title='recon combined sum xy', | |
2558 path=self.output_folder, save_fig=self.save_plots, | |
2559 save_only=self.save_plots_only) | |
2560 np.savetxt(f'{self.output_folder}/recon_combined.txt', | |
2561 tomo_recon_combined[int(tomosum.size/2),:,:], fmt='%.6e') | |
2501 else: | 2562 else: |
2502 base_name = 'recon combined' | 2563 base_name = 'recon combined' |
2503 for stack in stacks: | 2564 for stack in stacks: |
2504 base_name += f' {stack["index"]}' | 2565 base_name += f' {stack["index"]}' |
2505 self._saveTomo(base_name, tomo_recon_combined) | 2566 self._saveTomo(base_name, tomo_recon_combined) |