├── .gitignore ├── README.md ├── aux_gen_resized_previews.py ├── aux_gen_simple_previews.py ├── aux_make_resized.py ├── aux_segm_result_as_gif.py ├── config.json ├── ct_reg_segmentor.py ├── fine_walker.py ├── go_a_calc_lungproj.py ├── go_b_collect_lungproj.py ├── go_c_regsegm.py ├── lungproj_xyzb_130_py.txt ├── regFiles ├── EntireTransformParameters.txt ├── FinalTransformParameters.txt ├── HeartTransformParameters.txt └── parameters_BSpline.txt ├── regsegm_logging.py ├── regsegm_utils.py ├── resized_data └── .gitignore ├── result1.gif ├── result2.gif ├── run_regsegm.py └── test_data ├── .gitignore └── dir_with_images └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | #### Directories to ignore for GIT 2 | # service git folder 3 | .git/ 4 | # service pyCharm folders 5 | .idea/ 6 | __pycache__/ 7 | 8 | #### Files to ignore for GIT 9 | # compiled python files 10 | *.pyc 11 | 12 | #### User files and folders 13 | registration_py/ 14 | *.nii.gz 15 | tmp* 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CT_RegSegm 2 | Segmentation of lungs in 3D Computed Tomography (CT) scans via non-rigid image registration scheme [\[1\]](#references). 3 | 4 | Short description of the current implementation can be found in [\[2\]](#references) (please consider citing if using this implementation). 5 | 6 | ### Requirements 7 | 8 | Running the scripts requires 9 | * __Python 3.6+__ with the following packages installed 10 | (all installable via *pip*): 11 | 12 | ``` 13 | numpy 14 | scikit-image 15 | scipy 16 | pandas 17 | nibabel 18 | imageio 19 | ``` 20 | 21 | * __Elastix__ tool installed in your `PATH`. 22 | The tool can be downloaded from the website (http://elastix.isi.uu.nl/) 23 | or installed on Unix systems via: 24 | 25 | ``` 26 | sudo apt install elastix 27 | ``` 28 | 29 | __NOTE__: the Elastix official website seems to be not working, therefore you can try to download Elastix for Windows 30 | __[here](https://drive.google.com/open?id=1bF5O7UXJJll2N7mo-uFQX6m8xcBKxz-u)__. 31 | 32 | * Download the __[CT_RegSegm_data.tar](https://drive.google.com/open?id=1x6nM5Z4_o8S_7DInp2rgqCwFoxrcMLpb) (289 MB)__ 33 | archive and extract its content (`resized_data` and `test_data`) 34 | into the repository root directory. 35 | 36 | ### Running the scripts 37 | 38 | The scripts can be run directly from Python (see [go_c_regsegm.py](go_c_regsegm.py)) 39 | or from command line using [run_regsegm.py](run_regsegm.py) script. Examples: 40 | 41 | ``` 42 | python3 run_regsegm.py test_data/test_image.nii.gz 43 | python3 run_regsegm.py test_data/dir_with_images 44 | ``` 45 | 46 | If succeeded, the `*_regsegm_py.nii.gz` files containing the lung masks should appear next to the original files. 47 | 48 | Result examples: 49 | 50 | ![Alt_text](result1.gif) ![Alt_text](result2.gif) 51 | 52 | ### References 53 | 54 | [1] Sluimer I, Prokop M, van Ginneken B. Toward automated 55 | segmentation of the pathological lung in CT. IEEE Trans 56 | Med Imaging 2005;24(8):1025–1038. 57 | (URL: https://www.ncbi.nlm.nih.gov/pubmed/16092334) 58 | 59 | [2] Liauchuk, V., Kovalev, V.: ImageCLEF 2017: Supervoxels and co-occurrence for 60 | tuberculosis CT image classification. 61 | In: CLEF2017 Working Notes. CEUR Workshop Proceedings, Dublin, Ireland, 62 | CEUR-WS.org (September 11-14 2017) 63 | (URL: http://ceur-ws.org/Vol-1866/paper_146.pdf). 64 | -------------------------------------------------------------------------------- /aux_gen_resized_previews.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from skimage import io, transform 4 | 5 | 6 | def main(): 7 | data_dir = 'resized_data' 8 | 9 | for i in range(1, 131): 10 | for postfix in ['img', 'msk']: 11 | path = os.path.join(data_dir, 'id%03i_%s.npz' % (i, postfix)) 12 | 13 | data = np.load(path) 14 | img = data[data.files[0]] 15 | 16 | shape2d = (img.shape[0], img.shape[1]) 17 | im1 = img[:, :, img.shape[2] // 2] 18 | im1 = transform.resize(im1, shape2d) 19 | im2 = img[:, img.shape[1] // 2, :] 20 | im2 = transform.resize(im2, shape2d) 21 | im3 = img[img.shape[0] // 2, :, :] 22 | im3 = transform.resize(im3, shape2d) 23 | 24 | im = np.concatenate([im1, np.transpose(im2), np.transpose(im3)], axis=1) 25 | im = np.flipud(im) 26 | 27 | out_path = path[:-4] + '_preview.png' 28 | print('Saving preview to ' + out_path) 29 | io.imsave(out_path, im) 30 | 31 | 32 | if __name__ == '__main__': 33 | main() 34 | -------------------------------------------------------------------------------- /aux_gen_simple_previews.py: -------------------------------------------------------------------------------- 1 | import os 2 | import nibabel as nb 3 | import numpy as np 4 | from glob import glob 5 | from skimage import io 6 | from skimage.transform import resize 7 | 8 | 9 | def gen_frontal_slice_previews(dir_with_nifti): 10 | ext = '.nii.gz' 11 | 12 | out_dir = os.path.join(dir_with_nifti, 'previews') 13 | os.makedirs(out_dir, exist_ok=True) 14 | 15 | paths = glob(os.path.join(dir_with_nifti, '*' + ext)) 16 | for path in paths: 17 | nii = nb.load(path) 18 | im3 = nii.get_data() 19 | 20 | im = im3[:, 256, :].astype(float) 21 | im = (im - im.min()) / (im.max() - im.min()) 22 | im = resize(im, (256, 256)) 23 | im = im.T[::-1] 24 | 25 | name = os.path.split(path)[1][:-len(ext)] 26 | out_path = os.path.join(out_dir, name + '.png') 27 | print(out_path) 28 | io.imsave(out_path, (im * 255).astype(np.uint8)) 29 | 30 | 31 | if __name__ == '__main__': 32 | gen_frontal_slice_previews('path/to/dir/with/nifti') 33 | -------------------------------------------------------------------------------- /aux_make_resized.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import numpy as np 4 | 5 | import regsegm_utils as reg 6 | 7 | 8 | def main(): 9 | with open('config.json', 'r') as f: 10 | config = json.load(f) 11 | 12 | dir_initial = '/path/to/original/images' 13 | dir_segmented = '/path/to/segmented/images' 14 | 15 | out_dir = 'resized_data' 16 | 17 | os.makedirs(out_dir, exist_ok=True) 18 | 19 | rs = config['slice_resize'] 20 | pos_val = config['positive_value'] 21 | 22 | for i in range(1, 131): 23 | img_path = os.path.join(dir_initial, 'id%03i.nii.gz' % i) 24 | msk_path = os.path.join(dir_segmented, 'id%03i_resegm2.nii.gz' % i) 25 | 26 | print('Reading ' + img_path) 27 | img = reg.adv_analyze_nii_read(img_path)[0] 28 | img = reg.make_uint8(img) 29 | img = img[::rs, ::rs, :] 30 | 31 | out_path = os.path.join(out_dir, 'id%03i_img.npz' % i) 32 | print('Saving resized image to ' + out_path) 33 | np.savez_compressed(out_path, img) 34 | 35 | print('Reading ' + msk_path) 36 | msk = reg.adv_analyze_nii_read(msk_path)[0] 37 | msk = reg.make_uint8(msk) 38 | msk[msk > 0] = pos_val 39 | msk[msk == 0] = 0 40 | msk = msk[::rs, ::rs, :] 41 | 42 | out_path = os.path.join(out_dir, 'id%03i_msk.npz' % i) 43 | print('Saving resized mask to ' + out_path) 44 | np.savez_compressed(out_path, msk) 45 | 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /aux_segm_result_as_gif.py: -------------------------------------------------------------------------------- 1 | import imageio 2 | import numpy as np 3 | from skimage import transform 4 | 5 | import regsegm_utils as reg 6 | from ct_reg_segmentor import CtRegSegmentor 7 | 8 | 9 | if __name__ == '__main__': 10 | rs = CtRegSegmentor() 11 | 12 | rs.process_dir('test_data/dir_with_images') 13 | 14 | img_path = 'test_data/dir_with_images/image1.nii.gz' 15 | out_path = 'result1.gif' 16 | msk_path = img_path.replace('.nii.gz', '_regsegm_py.nii.gz') 17 | 18 | img = reg.adv_analyze_nii_read(img_path)[0] 19 | img[img < 0] = 0 20 | msk = reg.adv_analyze_nii_read(msk_path)[0] 21 | 22 | ground = msk.min() 23 | 24 | images = [] 25 | for k in range(10, img.shape[2] - 10, 2): 26 | if k % 10 == 0: 27 | print('%i / %i' % (k, img.shape[2])) 28 | 29 | slice = img[:, :, k:k + 1] / 1500 30 | 31 | mask_slice = msk[:, :, k:k + 1] == ground 32 | 33 | shadowed = slice * mask_slice 34 | 35 | rgb = np.concatenate((slice, slice, shadowed), axis=2) 36 | rgb = transform.resize(rgb, (256, 256)) 37 | rgb = np.flipud(rgb) 38 | 39 | rgb += 0.1 40 | rgb[rgb > 1] = 1 41 | 42 | images.append((rgb * 255).astype(np.uint8)) 43 | 44 | print('Writing gif to ' + out_path) 45 | imageio.mimsave(out_path, images, duration=1./20) 46 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_resize": 4, 3 | "positive_value": 200, 4 | "num_nearest": 5, 5 | "smooth_sigma": 1 6 | } -------------------------------------------------------------------------------- /ct_reg_segmentor.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import shutil 4 | import traceback 5 | import pandas as pd 6 | import numpy as np 7 | from scipy.spatial import distance_matrix 8 | from scipy.ndimage import gaussian_filter 9 | import regsegm_utils as reg 10 | from regsegm_logging import logmess 11 | 12 | 13 | class CtRegSegmentor(): 14 | """Creates an instance of CtRegSegmentor class which can be used for segmentation of lung regions in 3D Computed 15 | Tomography (CT) images of chest. 16 | 17 | # Arguments 18 | config_file_path: (str) Path to JSON configuration file. Defaults to 'config.json' 19 | resized_data_dir: (str) Path to directory with the resized image data (id*_img.npz files). 20 | Defaults to 'resized_data' 21 | reg_dir: (str) Path to the directory which will be created for storing the temporary files. 22 | Defaults to 'registration_py' 23 | reg_files_storage: (str) Path to directory with files storing the 'elastix' parameters. Defaults to 'regFiles'. 24 | swap_x: (bool): Whether to swap X axis at input and output. Defaults to False. 25 | swap_y: (bool): Whether to swap Y axis at input and output. Defaults to False. 26 | lungs_proj_file_path: (str) Path to the file with projections information. 27 | Defaults to 'lungproj_xyzb_130_py.txt'. 28 | 29 | # Examples 30 | `.process_file('test_data/test_image.nii.gz')` 31 | `.process_dir('test_data/dir_with_images')` 32 | 33 | """ 34 | 35 | def __init__(self, config_file_path='config.json', 36 | resized_data_dir='resized_data', 37 | reg_dir='registration_py', 38 | reg_files_storage='regFiles', 39 | swap_x=False, swap_y=False, 40 | lungs_proj_file_path='lungproj_xyzb_130_py.txt'): 41 | 42 | self.config_file_path = config_file_path 43 | self.resized_data_dir = resized_data_dir 44 | self.reg_dir = reg_dir 45 | self.reg_files_storage = reg_files_storage 46 | self.swap_x = swap_x 47 | self.swap_y = swap_y 48 | self.lungs_proj_file_path = lungs_proj_file_path 49 | 50 | def process_file(self, file_path): 51 | """Reads a Nifti image, performs segmentation of lungs and saves the result into '*_regsegm.nii.gz' file. 52 | 53 | # Arguments 54 | file_path: (str) Path to the input file 55 | 56 | """ 57 | 58 | os.makedirs(self.reg_dir, exist_ok=True) 59 | 60 | logmess(self.reg_dir) 61 | 62 | self._copy_files_from_storage() 63 | 64 | with open(self.config_file_path, 'r') as f: 65 | config = json.load(f) 66 | 67 | num_nearest = config['num_nearest'] 68 | resz = config['slice_resize'] 69 | pos_val = config['positive_value'] 70 | 71 | logmess(self.reg_dir, 'Reading lung projections from ' + self.lungs_proj_file_path) 72 | df = pd.read_csv(self.lungs_proj_file_path, header=None) 73 | data = np.asarray(df) 74 | xyz_bounds = data[:, 300:306] 75 | lung_projs = data[:, 0:300] 76 | 77 | self._log('Reading 3D image from ' + file_path) 78 | im, vox_dim, affine, shape0 = reg.adv_analyze_nii_read(file_path, swap_x=self.swap_x, swap_y=self.swap_y) 79 | 80 | self._log('Coarse extraction of lungs') 81 | lungs = reg.catch_lungs(im, vox_dim) 82 | self._log('Calculating lung projections') 83 | projections, bounds = reg.calculate_lung_projections(lungs, vox_dim) 84 | 85 | distances = distance_matrix(projections, lung_projs).flatten() 86 | idx = np.argsort(distances) 87 | if distances[idx[0]] < 0.001: 88 | ids = idx[1:num_nearest + 1] + 1 89 | else: 90 | ids = idx[0:num_nearest] + 1 91 | 92 | fixed = reg.make_uint8(im[::resz, ::resz, :]).copy() 93 | mean_mask = (fixed * 0).astype(np.float32) 94 | for j in range(num_nearest): 95 | bounds_moving = xyz_bounds[ids[j] - 1, :] 96 | 97 | path = os.path.join(self.resized_data_dir, 'id%03i_img.npz' % ids[j]) 98 | self._log('Similar image #%i: Reading image from %s' % (j + 1, path)) 99 | data = np.load(path) 100 | moving = data[data.files[0]] 101 | moving = self._shift3(moving, fixed.shape, bounds_moving // resz, bounds // resz).astype(np.uint8) 102 | 103 | path = os.path.join(self.resized_data_dir, 'id%03i_msk.npz' % ids[j]) 104 | self._log('Similar image #%i: Reading mask from %s' % (j + 1, path)) 105 | data = np.load(path) 106 | mask = data[data.files[0]] 107 | mask = self._shift3(mask, fixed.shape, bounds_moving // resz, bounds // resz).astype(np.uint8) 108 | 109 | self._log('Similar image #%i: Registration' % (j + 1)) 110 | moved_mask = reg.register3d(moving, fixed, mask, self.reg_dir) 111 | 112 | mean_mask += moved_mask.astype(np.float32) / pos_val / num_nearest 113 | 114 | self._log('Resizing procedures') 115 | mean_mask = reg.imresize(mean_mask, shape0, order=1) 116 | if config['smooth_sigma'] > 0: 117 | z_sigma = config['smooth_sigma'] * vox_dim[2] / vox_dim[1] 118 | mean_mask = gaussian_filter(mean_mask, (1, 1, z_sigma)) 119 | mean_mask = np.array(mean_mask > 0.5) 120 | 121 | out_path = file_path[:-7] + '_regsegm_py.nii.gz' 122 | self._log('Saving result to ' + out_path) 123 | reg.save_as_nii(mean_mask, affine, out_path, swap_x=self.swap_x, swap_y=self.swap_y) 124 | 125 | return 0 126 | 127 | def process_dir(self, dir_path): 128 | """Reads Nifti (*.nii.gz) images from the specified directory, performs segmentation of lungs and saves the results 129 | into '*_regsegm.nii.gz' files. 130 | 131 | # Arguments 132 | dir_path: (str) Path to the directory with Nifti images. 133 | 134 | """ 135 | 136 | file_ending = '.nii.gz' 137 | files = os.listdir(dir_path) 138 | 139 | skipped = 0 140 | processed = 0 141 | failed = 0 142 | for file in files: 143 | file_path = os.path.join(dir_path, file) 144 | out_path = os.path.join(dir_path, file[:-7] + '_regsegm_py.nii.gz') 145 | 146 | if file.endswith(file_ending) and '_regsegm' not in file: 147 | if os.path.isfile(out_path): 148 | print('File ' + out_path + ' already exists. Skipping.') 149 | skipped += 1 150 | else: 151 | print('Processing "' + file + '"') 152 | try: 153 | self.process_file(file_path) 154 | processed += 1 155 | except: 156 | print('*** FAILED to process files "' + file + '"') 157 | failed += 1 158 | traceback.print_exc() 159 | 160 | print('Finished processing images in ' + dir_path) 161 | print('Skipped: %i\nProcessed: %i\nFailed: %i' % (skipped, processed, failed)) 162 | 163 | def _log(self, message=None): 164 | if message is None: 165 | logmess(self.reg_dir) 166 | else: 167 | logmess(self.reg_dir, message) 168 | 169 | @staticmethod 170 | def _shift3(im, sz, xyzsrc, xyztrg): 171 | mult = 1.0e-5 172 | im = im.astype(np.float32) * mult 173 | 174 | for dim in [2, 1, 3]: 175 | srange = xyzsrc[2 * dim - 2:2 * dim].astype(np.float32) 176 | trange = xyztrg[2 * dim - 2:2 * dim].astype(np.int) 177 | 178 | resz = (trange[1] - trange[0]) / (srange[1] - srange[0]) 179 | newsz = (int(round(im.shape[0] * resz)), im.shape[1], im.shape[2]) 180 | im1 = reg.imresize(im, newsz, order=0) 181 | 182 | if dim == 3: 183 | shp = (sz[2], im.shape[1], im.shape[2]) 184 | im = np.zeros(shp) 185 | else: 186 | im = im * 0 187 | 188 | n = trange[1] - trange[0] 189 | 190 | strt = int(round(srange[0] * resz)) 191 | if strt - trange[0] + 1 > 0: 192 | im[0:trange[0], :, :] = im1[strt - trange[0]:strt, :, :] 193 | else: 194 | im[trange[0] - strt:trange[0], :, :] = im1[0:strt, :, :] 195 | 196 | im[trange[0]:(trange[0] + n), :, :] = im1[strt:(strt + n), :, :] 197 | 198 | if strt + n + im.shape[0] - trange[1] <= im1.shape[0]: 199 | im[trange[1]:im.shape[0], :, :] = im1[strt + n:strt + n + im.shape[0] - trange[1], :, :] 200 | else: 201 | im[trange[1]:trange[1] + im1.shape[0] - strt - n, :, :] = im1[strt + n:im1.shape[0], :, :] 202 | 203 | im = np.swapaxes(im, 0, 1) 204 | im = np.swapaxes(im, 1, 2) 205 | 206 | if im.shape[2] > sz[2]: 207 | im = im[:, :, 0:sz[2]] 208 | elif im.shape[2] < sz[2]: 209 | im_ = np.zeros(sz, dtype=im.dtype) 210 | im_[:, :, 0:im.shape[2]] = im 211 | im = im_ 212 | 213 | im = im / mult 214 | return im 215 | 216 | def _copy_files_from_storage(self): 217 | logmess(self.reg_dir, 'Copying files from ' + self.reg_files_storage) 218 | 219 | files = os.listdir(self.reg_files_storage + '/') 220 | for file in files: 221 | if file.endswith('.txt'): 222 | src = os.path.join(self.reg_files_storage, file) 223 | dst = os.path.join(self.reg_dir, file) 224 | shutil.copyfile(src, dst) 225 | 226 | 227 | if __name__ == '__main__': 228 | print('Testing CtRegSegmentor') 229 | CtRegSegmentor().process_file('test_data/test_image.nii.gz') 230 | -------------------------------------------------------------------------------- /fine_walker.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from time import time 4 | from skimage import io 5 | from skimage.color import hsv2rgb 6 | from skimage.morphology import binary_erosion, thin 7 | from skimage.segmentation import random_walker 8 | import regsegm_utils as reg 9 | 10 | 11 | class FineWalker: 12 | """Creates an instance of FineWalker class which can be used for correction of borders of the segmented 13 | lung regions in 3D Computed Tomography (CT) images of chest. 14 | The correction of borders is done by shrinking the 'mask' and 'not-mask' regions and performing re-segmentation of 15 | the newly-formed region in between which is supposed to contain the true border of lung regions. 16 | The re-segmentation of border region is made using Random Walker Segmentation algorithm. Here the shrunk 'mask' 17 | and 'not-mask' regions are treated as seed labels for the algorithm. 18 | 19 | # Arguments 20 | erosion_r: (int) Radius in pixel units (of axial slice) of the structuring element to perform the erosions. 21 | Defaults to 7. 22 | erosion_flat: (bool) If set to True, the erosions are performed in a slice-wise manner in 2D. 23 | Otherwise the erosions are performed in 3D with use of 3D structuring element. Defaults to True. 24 | thinnings: (int) Number of 2D thinning operations applied in a slice-wise manner after the erosions. 25 | Defaults to 5. 26 | kernel_size: (int) Number of axial CT slices used to run the Random Walker algorithm. When set to 1, the Random 27 | Walker is performed in 2D. Warning: using large values may significantly increase the processing time. 28 | Defaults to 1. 29 | stride: (int) Z-axis stride of the sliding window to perform the Random Walker algorithm. 30 | Defaults to 1. 31 | 32 | # Examples 33 | `.process_image_mask('image.nii.gz', 'mask.nii.gz', 'result.nii.gz')` 34 | `.process_image_mask('image.nii.gz', 'mask.nii.gz')` 35 | 36 | """ 37 | 38 | def __init__(self, erosion_r=7, erosion_flat=True, thinnings=5, kernel_size=1, stride=1): 39 | self.erosion_r = erosion_r 40 | self.thinnings = thinnings 41 | self.erosion_flat = erosion_flat 42 | self.kernel_size = kernel_size 43 | self.stride = stride 44 | 45 | def process_image_mask(self, image_path, mask_path, out_path=None): 46 | """Reads a Nifti CT image, the existing lungs mask and performs correction of borders. 47 | 48 | # Arguments 49 | image_path: (str) Path to the input file with CT image. 50 | mask_path: (str) Path to the input file with the existing lungs mask. 51 | out_path: (str or None, optional) Path to the output file. 52 | If not specified, the output file path is generated automatically. 53 | 54 | """ 55 | 56 | im, voxel_dimensions, affine, shape0 = reg.adv_analyze_nii_read(image_path) 57 | im = reg.make_uint8(im) 58 | 59 | msk, _, _, _ = reg.adv_analyze_nii_read(mask_path) 60 | msk = np.array(msk > msk.min()) 61 | 62 | inner, outer = self._preprocess_lung_mask(msk, voxel_dimensions) 63 | 64 | accum_inner = self._perform_random_walk(im, inner, outer) 65 | 66 | if out_path is None: 67 | out_path = self._compose_out_path(image_path) 68 | 69 | print('Saving to ' + out_path) 70 | reg.save_as_nii(accum_inner, affine, out_path) 71 | 72 | # print('Here are some illustrations') 73 | # accum_inner[accum_inner == 0] = 2 74 | # for c in [1, 15, 30, 60, 100, -2]: 75 | # self._compose_images_for_slice(im[..., c], msk[..., c], inner[..., c], outer[..., c], accum_inner[..., c]) 76 | 77 | def _preprocess_lung_mask(self, msk, voxel_dimensions): 78 | print('Eroding') 79 | start_time = time() 80 | selem = self._make_structure_element(voxel_dimensions) 81 | inner = binary_erosion(msk, selem=selem) 82 | outer = binary_erosion(np.logical_not(msk), selem=selem) 83 | print('Eroding took %.3f sec' % (time() - start_time)) 84 | 85 | print('Thinning') 86 | start_time = time() 87 | for k in range(msk.shape[2]): 88 | inner[..., k] = thin(inner[..., k], max_iter=self.thinnings) 89 | outer[..., k] = thin(outer[..., k], max_iter=self.thinnings) 90 | print('Thinning took %.3f sec' % (time() - start_time)) 91 | 92 | return inner, outer 93 | 94 | def _perform_random_walk(self, im, inner, outer): 95 | labels = np.zeros(im.shape, dtype='int16') 96 | labels[inner] = 1 97 | labels[outer] = 2 98 | 99 | accum_inner, accum = im * 0, im * 0 100 | print('Random walking') 101 | ds = self.kernel_size // 2 102 | start_time = time() 103 | for k in range(ds, im.shape[2] - self.kernel_size + ds, self.stride): 104 | slice_start = k - ds 105 | slice_end = k - ds + self.kernel_size 106 | 107 | for i, side in enumerate(['left', 'right']): 108 | x_start = (im.shape[1] // 2 - 1) * i 109 | x_end = x_start + im.shape[1] // 2 110 | im_part = im[:, x_start:x_end, slice_start:slice_end] 111 | lbl_part = labels[:, x_start:x_end, slice_start:slice_end] 112 | 113 | if np.any(lbl_part == 1) and np.any(lbl_part == 2): 114 | print('%i / %i (%s)' % (k, im.shape[2], side)) 115 | 116 | out_labels = random_walker(im_part, lbl_part) 117 | accum_inner[:, x_start:x_end, slice_start:slice_end] += out_labels == 1 118 | accum[:, x_start:x_end, slice_start:slice_end] += 1 119 | 120 | print('Random walk took %.3f sec' % (time() - start_time)) 121 | accum[accum == 0] = 1 122 | accum_inner = accum_inner * 10 // accum 123 | accum_inner[accum_inner < 5] = 0 124 | accum_inner[accum_inner > 0] = 1 125 | return accum_inner 126 | 127 | def _make_structure_element(self, voxel_dimensions): 128 | if self.erosion_flat: 129 | rz = 0 130 | else: 131 | z2xy = voxel_dimensions[2] / voxel_dimensions[0] 132 | rz = round(self.erosion_r / z2xy) 133 | 134 | xy_values = np.linspace(-1, 1, 2 * self.erosion_r + 3) 135 | z_values = np.linspace(-1, 1, 2 * rz + 3) 136 | xx, yy, zz = np.meshgrid(xy_values, xy_values, z_values) 137 | selem = (xx ** 2 + yy ** 2 + zz ** 2) < 1 138 | selem = selem[1:-1, 1:-1, 1:-1] 139 | return selem 140 | 141 | def _compose_out_path(self, image_path): 142 | ext = self._detect_extension(image_path) 143 | 144 | base = image_path[:-len(ext)] if len(ext) > 0 else image_path 145 | flat_char = 'f' if self.erosion_flat else '' 146 | out_path = f'{base}_e{self.erosion_r}{flat_char}_t{self.thinnings}_k{self.kernel_size}_s{self.stride}{ext}' 147 | 148 | return out_path 149 | 150 | @staticmethod 151 | def _detect_extension(path): 152 | known_extensions = ['.nii.gz', '.nii', '.hdr', '.img'] 153 | 154 | for e in known_extensions: 155 | if path.endswith(e): 156 | return e 157 | 158 | return os.path.splitext(path)[1] 159 | 160 | @staticmethod 161 | def _compose_images_for_slice(im, msk, inner, outer, out_labels): 162 | def colorize_regions(image, region1, region2, h1=0.35, h2=0., s1=0.7, s2=0.7): 163 | hsv = np.zeros(image.shape + (3,), dtype=float) 164 | hsv[..., 2] = 0.5 + 0.5 * image / 255. 165 | hsv[..., 1] = region1 * s1 + region2 * s2 166 | hsv[..., 0] = h1 * region1 + h2 * region2 167 | return hsv2rgb(hsv) 168 | 169 | original_segm = colorize_regions(im, msk, 1 - msk) 170 | inner_and_outer = colorize_regions(im, inner, outer) 171 | walker_results = colorize_regions(im, out_labels == 1, out_labels == 2) 172 | 173 | io.imshow_collection((original_segm, inner_and_outer, walker_results)) 174 | io.show() 175 | 176 | 177 | if __name__ == '__main__': 178 | fw = FineWalker() 179 | for path in ['test_data/test_image.nii.gz', 'test_data/dir_with_images/image1.nii.gz', 180 | 'test_data/dir_with_images/image2.nii.gz']: 181 | fw.process_image_mask(path, path.replace('.nii.gz', '_regsegm_py.nii.gz')) 182 | -------------------------------------------------------------------------------- /go_a_calc_lungproj.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import regsegm_utils as reg 4 | 5 | 6 | def save_lungproj(filename): 7 | im, pxdim, affine = reg.adv_analyze_nii_read(filename) 8 | 9 | lng = reg.catch_lungs(im, pxdim) 10 | proj, xyzb = reg.calculate_lung_projections(lng, pxdim) 11 | 12 | result = np.append(proj, xyzb) 13 | result = np.asarray([result]) 14 | 15 | fno = filename[:-7] + '_lungproj_py.txt' 16 | df = pd.DataFrame(result) 17 | df.to_csv(fno, header=False, index=False) 18 | 19 | return 0 20 | 21 | 22 | def main(): 23 | dr = '/path/to/original/images/' 24 | 25 | for i in range(130): 26 | fn = 'id%03i.nii.gz' % (i + 1) 27 | path = dr + '/' + fn 28 | 29 | print('Processing "' + fn + '"') 30 | save_lungproj(path) 31 | 32 | print('FINISHED') 33 | 34 | 35 | if __name__ == '__main__': 36 | main() 37 | -------------------------------------------------------------------------------- /go_b_collect_lungproj.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | 4 | 5 | def main(): 6 | dr = '/path/to/original/images/' 7 | 8 | tbl = None 9 | for i in range(130): 10 | fn = 'id%03i_lungproj_py.txt' % (i + 1) 11 | path = dr + '/' + fn 12 | 13 | print('Reading "' + fn + '"') 14 | row = pd.read_csv(path, header=None).get_values() 15 | 16 | if tbl is None: 17 | tbl = row 18 | else: 19 | tbl = np.append(tbl, row, axis=0) 20 | 21 | fno = 'lungproj_xyzb_130_py.txt' 22 | print('Saving table to "' + fno + '"') 23 | df = pd.DataFrame(tbl) 24 | df.to_csv(fno, header=False, index=False) 25 | 26 | print('FINISHED') 27 | 28 | 29 | if __name__ == '__main__': 30 | main() 31 | -------------------------------------------------------------------------------- /go_c_regsegm.py: -------------------------------------------------------------------------------- 1 | from ct_reg_segmentor import CtRegSegmentor 2 | 3 | 4 | if __name__ == '__main__': 5 | rs = CtRegSegmentor() 6 | 7 | rs.process_file('test_data/test_image.nii.gz') 8 | 9 | rs.process_dir('test_data/dir_with_images') 10 | -------------------------------------------------------------------------------- /regFiles/EntireTransformParameters.txt: -------------------------------------------------------------------------------- 1 | (Transform "BSplineTransform") 2 | (NumberOfParameters 3993) 3 | (TransformParameters -0.047490 -0.240089 -0.361630 -0.487581 -0.555947 -0.546097 -0.427382 -0.258240 -0.092723 0.026459 0.104400 0.098243 -0.148337 -0.466237 -0.828182 -1.047874 -1.095917 -0.914180 -0.609285 -0.318434 -0.102222 0.120357 0.262338 0.094465 -0.308420 -0.811426 -1.186666 -1.361275 -1.233532 -0.888016 -0.542955 -0.262945 0.083046 0.502267 0.453752 -0.042302 -0.742238 -1.281225 -1.466618 -1.266719 -0.927308 -0.508395 -0.193998 0.121243 0.785570 0.918213 0.252546 -0.651855 -1.159077 -1.172637 -0.675935 -0.017313 0.406630 0.456504 0.347015 0.868683 1.056253 0.398265 -0.480642 -0.991016 -0.853204 -0.113774 0.673982 0.966455 1.072347 0.585597 0.507095 0.474370 -0.022689 -0.646864 -0.942170 -0.817259 -0.115283 0.812185 1.075883 1.158767 0.660313 0.034391 -0.262471 -0.520409 -0.829604 -0.969035 -0.895703 -0.328872 0.443400 0.861141 0.995889 0.655373 -0.208369 -0.587509 -0.699531 -0.790709 -0.912225 -0.836591 -0.514411 0.012684 0.596196 0.851975 0.644273 -0.291564 -0.645976 -0.761186 -0.835358 -0.840826 -0.686604 -0.371172 0.062467 0.492747 0.747740 0.619645 -0.203444 -0.344176 -0.356273 -0.330685 -0.249009 -0.122813 0.042398 0.229536 0.413066 0.530765 0.421678 0.174691 -0.032260 -0.266149 -0.516519 -0.636881 -0.614758 -0.425892 -0.174024 0.040557 0.178265 0.204173 0.689128 0.481787 -0.148902 -0.863792 -1.217414 -1.429146 -1.182543 -0.599496 -0.325987 -0.165534 0.088857 1.106648 1.127022 0.699878 -0.161625 -0.999312 -2.120138 -2.199975 -1.336171 -1.031528 -0.735352 -0.164455 1.654738 1.724877 1.611836 -0.140114 -1.782024 -2.035201 -1.992715 -2.627601 -1.803363 -1.032159 -0.337892 2.300866 2.413967 1.503830 -0.671805 -1.629963 -1.465665 -0.867664 -0.279768 0.397589 -0.223985 -0.150432 2.420691 2.627415 1.395445 -0.810400 -1.831882 -1.353649 -0.272886 0.554802 0.057813 0.451753 0.168591 1.424452 1.551704 0.090004 -1.562229 -1.550147 -1.961667 -0.983350 1.675045 0.343980 0.669727 0.395395 0.084957 -0.233247 -0.302409 -1.105486 -1.875994 -2.707409 -1.727524 0.021538 0.239407 0.716095 0.551433 -0.633993 -1.582861 -1.186557 -0.993200 -1.977457 -2.644676 -2.652074 -2.100081 -0.180784 0.645873 0.647713 -0.901689 -1.970270 -2.238843 -2.498711 -2.754916 -2.706189 -2.295653 -1.338337 -0.137226 0.554280 0.680434 -0.722230 -1.330039 -1.475106 -1.570698 -1.558175 -1.391864 -0.991539 -0.468753 0.058725 0.431092 0.505268 0.345718 0.177946 -0.098958 -0.383878 -0.476327 -0.404908 -0.183873 0.081203 0.282320 0.393369 0.306331 1.005019 0.823926 0.179918 -0.419848 -0.749597 -0.935684 -0.456799 0.124594 0.197921 0.185363 0.207913 1.443725 1.460290 0.721506 0.325910 -0.739844 -1.834977 -0.168188 0.623077 -0.289877 -0.479194 -0.136566 1.913247 1.509653 1.895492 0.076258 -2.507780 -1.322504 0.897379 -0.419094 -1.456848 -1.227154 -0.506490 2.536155 1.578183 2.103581 -0.247211 -2.907513 -1.342901 -0.306405 -0.774459 -1.597405 -1.417799 -0.639498 2.671479 1.976835 0.500052 -1.190184 -1.483845 -0.806169 -0.142072 0.119628 -0.430869 -1.115822 -0.524212 1.592952 1.863489 -0.574372 -1.797848 -1.136318 -2.225136 -1.199358 0.300577 -0.890883 -0.752353 -0.143248 -0.014957 -0.143529 0.087836 -1.189150 -3.679085 -3.789052 -1.808821 -1.938058 -1.946129 -0.259986 0.297885 -0.888472 -1.898388 -1.192701 -2.106772 -3.402958 -3.489273 -2.911671 -2.636072 -0.906019 0.224227 0.578822 -1.207309 -2.480348 -2.815695 -3.168740 -3.266015 -3.378405 -2.994119 -1.911998 -0.513703 0.411095 0.704948 -1.004822 -1.824760 -2.007280 -2.147729 -2.211605 -2.074936 -1.542812 -0.821583 -0.113931 0.383333 0.538560 0.493563 0.308287 -0.050346 -0.387214 -0.409171 -0.222068 0.081533 0.390861 0.583280 0.660340 0.437709 1.231583 0.937101 0.195487 -0.350262 -0.407009 -0.166794 0.537803 0.943100 0.887319 0.700692 0.417562 1.648323 1.417923 -0.267050 -0.277954 -0.528860 -0.353352 1.723251 1.486535 0.633610 0.020007 0.026885 2.112736 1.705097 -0.086683 0.175835 -1.245721 -0.410707 2.180784 1.647162 0.096276 -1.062272 -0.508785 2.791874 2.659904 1.352495 -0.037123 -2.950367 -1.331866 0.204109 -0.401533 -2.530324 -2.433425 -0.989952 2.913304 2.690521 0.057353 -1.273272 -1.194257 -1.386067 -0.949604 -1.134064 -2.281513 -2.932412 -1.120576 1.721768 2.546503 -1.074437 -1.682142 -0.986119 -2.251299 -3.101561 -3.554442 -2.283013 -2.115391 -0.603572 -0.238471 -0.879917 0.025194 -0.530977 -2.554664 -3.698323 -4.071161 -3.436166 -1.270538 -0.843944 0.112967 -1.242739 -2.447417 -0.612584 -1.144289 -3.189907 -5.367820 -5.259677 -2.814886 -0.877735 -0.025988 0.567978 -1.604755 -3.193249 -3.404087 -3.618303 -4.321780 -5.047061 -4.277853 -2.331429 -0.715108 0.362553 0.777986 -1.351015 -2.477423 -2.775009 -3.022020 -3.147525 -2.965508 -2.202212 -1.194550 -0.275318 0.351114 0.589704 0.491174 0.137203 -0.366636 -0.786836 -0.687682 -0.295851 0.184988 0.601676 0.816707 0.872692 0.558246 1.126612 0.426250 -0.636791 -1.333532 -0.611749 0.243407 1.238045 1.504240 1.443372 1.219213 0.695657 1.460998 0.889671 -1.075829 -2.451401 -0.554153 1.158356 1.914592 1.530036 1.275221 0.667341 0.383006 1.978491 2.098432 1.132037 2.076519 0.892845 1.447653 1.978181 3.035305 0.763168 -0.434369 -0.128078 2.650920 2.922733 1.015285 1.074990 -1.217846 -0.217469 1.628077 1.345518 -2.503945 -2.145617 -0.726525 2.832495 2.596073 0.404455 -1.599611 -1.541071 -1.454459 -1.583197 -2.522360 -3.624922 -3.055341 -0.985284 1.602161 2.648485 -0.148329 -2.427929 -1.874708 -0.399532 -2.242967 -1.970610 -2.811335 -2.189917 -0.484130 -0.583065 -1.843252 -0.271350 -1.666756 -2.675995 -1.618951 -3.212270 -2.065789 -0.650450 -0.490848 0.267697 -1.653197 -3.617034 -2.707988 -3.167257 -4.327849 -4.821121 -4.667496 -2.606410 -0.428984 0.314211 0.734805 -2.045931 -4.242439 -5.014685 -5.711582 -5.724045 -5.734215 -4.501851 -2.102049 -0.400584 0.588522 0.939131 -1.685270 -3.219195 -3.787496 -4.252041 -4.303396 -3.882965 -2.785990 -1.443888 -0.337504 0.370692 0.664875 0.302426 -0.264170 -0.867435 -1.366389 -1.296995 -0.883358 -0.120159 0.547264 0.888805 0.991275 0.663235 0.693449 -0.363985 -1.288590 -1.954410 -1.063160 -0.466154 1.408748 1.749893 1.808931 1.698422 1.030760 0.923610 0.284132 -1.350642 -3.671204 -0.075118 2.179778 3.186724 1.883466 1.731721 1.423147 0.886635 1.377127 1.735657 -0.067746 1.210335 2.415590 2.579443 1.848167 1.891064 1.268714 0.677733 0.559309 2.005665 1.832270 0.313294 2.855609 1.541565 -0.127826 1.878479 3.665597 -0.229094 -0.625644 0.075152 2.339494 2.542710 1.140719 -0.935587 -2.252494 -3.849818 -1.709135 -0.121630 -2.071400 -1.399513 -0.162739 1.165295 2.652011 0.664690 -0.835429 -2.341953 -3.455332 -1.501488 2.715081 0.252837 -0.564740 0.226993 -1.030822 -2.359798 -1.266527 -0.680146 -2.552146 -2.864770 -0.558975 1.892780 1.365856 0.804829 0.821228 -2.073254 -4.307664 -4.124471 -5.188982 -6.108020 -4.201013 -1.463967 -0.748622 0.747754 1.236287 1.157170 -2.431987 -5.048937 -6.123519 -7.145616 -7.102700 -6.011008 -3.540179 -1.162688 0.422779 1.190664 1.265696 -1.925122 -3.759806 -4.572096 -5.216316 -5.181352 -4.546839 -3.086091 -1.424100 -0.188640 0.538783 0.802188 -0.119211 -0.833167 -1.373679 -1.932646 -2.392253 -2.239251 -1.063446 0.061095 0.699727 0.968665 0.741799 -0.093934 -1.138673 -1.392144 -1.381583 -2.550274 -2.922369 0.088532 1.318711 1.922966 2.098287 1.410975 0.010108 -0.442610 0.387797 0.414245 1.485412 2.010751 2.946587 1.726855 2.226881 2.249826 1.502832 0.349306 1.147244 0.330381 2.649449 4.786706 3.078822 1.404625 0.310669 1.904399 2.149305 1.496602 1.187355 4.434947 1.783486 2.148524 1.021368 -2.121783 1.822079 2.876519 1.106191 1.618467 1.357286 1.298335 4.065586 1.683258 -1.585839 -3.757718 -6.260669 -1.143224 1.077485 0.583375 1.364605 1.310652 0.082008 1.927546 -0.210341 -1.562815 -1.108471 -3.615690 0.153026 3.069429 2.093131 2.047187 1.542014 -1.694764 -3.087460 -2.723343 0.333540 0.635304 -1.828201 1.222575 3.665422 3.359220 2.811004 1.830822 -2.438731 -4.459658 -4.377895 -4.067182 -4.230457 -3.766543 0.090899 2.046830 2.782803 2.721120 1.907430 -2.629265 -5.041116 -6.046342 -6.856763 -6.660641 -6.686500 -3.050127 0.346321 1.799448 2.275082 1.827630 -1.958906 -3.753723 -4.601950 -5.286232 -5.260973 -4.714284 -2.933201 -0.967778 0.300006 0.954816 1.033207 -0.662633 -1.511428 -1.922437 -2.502258 -3.529828 -3.612885 -2.175850 -0.613020 0.363283 0.854462 0.793912 -1.108557 -2.167776 -1.806998 -1.090199 -5.035259 -6.284699 -2.482041 0.504341 1.804270 2.379643 1.782996 -1.195178 -2.039107 -0.405623 2.875358 0.044090 -1.339440 0.796077 1.825347 2.643879 2.994720 2.134660 -1.110625 -0.998128 -0.295961 3.806467 4.728787 3.699148 1.848731 0.911981 3.240432 3.598439 2.491066 -0.688952 1.479897 0.620128 1.147018 0.191678 -1.557123 1.730975 2.291462 3.478424 3.942241 2.757795 -0.848582 -0.465369 -1.346602 -3.242959 -6.255430 -7.626049 -0.136740 2.466274 3.741284 4.254267 2.950837 -1.607666 -1.334509 -1.932882 -2.002376 -1.957129 -1.990381 2.024081 2.791040 4.486069 4.666374 3.028328 -2.500779 -3.152956 -0.932560 1.273362 1.399036 1.339682 2.875043 3.940253 5.262658 4.812304 2.992348 -2.780663 -4.211698 -3.664443 -3.410343 -3.461896 -2.707136 1.746235 3.848091 4.449127 4.243408 2.777342 -2.717046 -4.588856 -5.340844 -6.082685 -6.246907 -6.760727 -2.246909 1.713258 3.142793 3.456556 2.478554 -1.863218 -3.381827 -4.088067 -4.709488 -4.845281 -4.345615 -2.388896 -0.307795 0.912913 1.469212 1.301333 -1.207406 -2.219699 -2.540616 -3.065225 -3.989404 -4.174247 -2.894110 -1.208296 -0.012279 0.677529 0.800061 -2.206133 -3.649263 -3.400244 -2.794891 -5.312669 -7.146120 -4.251685 -0.412984 1.426393 2.447633 2.049269 -2.589128 -4.174611 -3.672915 -0.569895 -2.290998 -3.865490 -1.436912 1.257772 2.567507 3.434096 2.631314 -2.936979 -4.983122 -4.352472 -1.247276 -0.333146 1.656721 1.756680 1.972418 3.895076 4.574055 3.285674 -3.037498 -4.663992 -4.889117 -2.531772 -2.110714 -1.608787 2.066577 3.732134 5.007483 5.503015 3.837009 -3.137892 -5.438939 -5.836058 -4.831210 -7.076576 -5.566890 1.473868 5.389886 5.753135 6.121311 4.189480 -3.273901 -4.306334 -3.835936 -3.670441 -4.205452 -0.346565 3.171919 4.748498 6.046459 6.273747 4.175792 -3.344454 -3.457777 -1.280453 -1.018096 0.010825 1.798876 2.720695 3.885623 5.920064 5.990568 3.927778 -3.103732 -3.935238 -2.171504 -1.372695 -2.444577 -2.985448 1.285676 4.026257 5.003430 5.184256 3.492274 -2.729932 -4.001796 -4.016429 -4.180663 -5.152460 -5.876920 -1.562108 2.349807 3.835496 4.271345 3.014232 -1.681166 -2.769251 -3.165164 -3.508920 -3.688102 -3.209293 -1.494886 0.326659 1.412736 1.897757 1.520302 -1.575614 -2.696887 -2.956588 -3.354237 -4.083579 -4.371040 -3.202719 -1.570409 -0.296224 0.504570 0.762604 -2.977482 -4.788518 -4.826765 -4.664459 -5.810904 -7.493291 -4.813724 -1.134800 1.022842 2.345402 2.139022 -3.597545 -5.687562 -5.473470 -4.709852 -5.024063 -5.488242 -2.843048 0.303759 2.272816 3.531803 2.858002 -4.226081 -7.016658 -6.372735 -4.678247 -3.749276 -1.981908 -0.115865 1.828407 3.840431 4.947220 3.683142 -4.595793 -7.469309 -7.529160 -5.672761 -4.309046 -1.417497 1.711046 3.359892 5.188211 6.153693 4.378755 -4.707150 -7.694379 -8.766009 -7.440864 -5.650363 -2.163969 1.637798 4.308092 6.067508 6.911293 4.807444 -4.441985 -6.645180 -7.320766 -5.599069 -4.171347 -1.002060 1.962383 4.482156 6.165283 6.891100 4.753742 -3.946172 -5.005891 -4.334657 -3.335545 -1.079094 0.194395 1.796497 3.989874 5.707384 6.374984 4.403647 -3.271100 -3.983714 -2.643875 -1.658359 -1.447709 -2.247058 0.609968 3.403905 4.883760 5.510533 3.849496 -2.655958 -3.467107 -3.140239 -2.835729 -3.215741 -3.545006 -0.613783 2.474119 4.002255 4.607027 3.271564 -1.481219 -2.186488 -2.293077 -2.346998 -2.386633 -1.991767 -0.695087 0.762763 1.691756 2.120718 1.617019 -1.448352 -2.380053 -2.534492 -2.681477 -2.885891 -2.831654 -2.155509 -1.242286 -0.430759 0.120255 0.417256 -2.743518 -4.292941 -4.355406 -4.299777 -4.387160 -4.136730 -2.748357 -1.011336 0.420081 1.335298 1.362474 -3.282367 -5.069304 -5.034621 -4.712413 -4.222639 -3.461519 -1.938648 -0.183581 1.290736 2.215075 1.915526 -3.828975 -5.902163 -5.782568 -5.013791 -3.861503 -2.431327 -0.738904 0.949064 2.416566 3.293562 2.564848 -4.189855 -6.433698 -6.320608 -5.315429 -3.645592 -1.597511 0.372728 2.043070 3.459991 4.249783 3.119281 -4.263314 -6.483323 -6.504453 -5.393330 -3.408151 -1.156012 0.948131 2.755066 4.150356 4.861636 3.462198 -3.873498 -5.639021 -5.483573 -4.247833 -2.601455 -0.753186 1.124147 2.853232 4.172369 4.839384 3.423707 -3.235609 -4.365556 -3.849243 -2.849541 -1.579840 -0.302892 1.151718 2.645027 3.832375 4.447726 3.150308 -2.504821 -3.184100 -2.619067 -1.844490 -1.109312 -0.384212 0.947180 2.339498 3.353173 3.855327 2.722363 -1.893003 -2.344961 -1.964237 -1.435142 -1.030405 -0.493705 0.720480 2.001324 2.858064 3.247432 2.284763 -0.892221 -1.178917 -1.071177 -0.885966 -0.706598 -0.393291 0.211584 0.865685 1.318212 1.530781 1.109678 -0.720760 -1.583932 -1.982447 -2.368113 -2.559974 -2.590068 -2.443251 -2.187752 -1.845707 -1.518980 -0.716228 -1.239050 -2.630501 -3.244140 -3.778843 -3.875967 -3.717173 -3.407693 -3.010251 -2.457737 -1.944374 -0.841673 -1.387079 -2.841809 -3.399928 -3.868649 -3.955981 -3.781523 -3.444596 -2.971328 -2.218320 -1.638567 -0.615871 -1.526608 -3.009374 -3.533500 -3.973950 -3.924642 -3.509750 -3.090373 -2.454679 -1.655782 -1.077839 -0.241816 -1.625349 -3.094815 -3.563964 -3.885559 -3.772235 -3.281932 -2.624062 -1.838215 -1.005614 -0.374194 0.201007 -1.631082 -3.011040 -3.421498 -3.634852 -3.416929 -2.863574 -1.996637 -1.018666 -0.146980 0.440950 0.667896 -1.464759 -2.593626 -2.877116 -2.987717 -2.702766 -2.059687 -1.023325 0.052519 0.912748 1.343142 1.120511 -1.203935 -1.961245 -2.068751 -2.035732 -1.721891 -1.049463 0.005368 1.059101 1.831661 2.127959 1.508976 -0.907340 -1.262429 -1.084115 -0.814712 -0.635170 -0.012423 0.729653 1.560149 2.298905 2.577770 1.751708 -0.655026 -0.680383 -0.340340 0.070227 0.277272 0.628532 1.174269 1.827711 2.424371 2.718178 1.826756 -0.214005 0.003556 0.331803 0.727649 1.012964 1.251191 1.492766 1.732346 1.923971 1.985772 1.257199 -0.814141 -1.791620 -2.316817 -2.806404 -2.966251 -2.907975 -2.704606 -2.456848 -2.209583 -1.970442 -1.055846 -1.494026 -3.210661 -4.059249 -4.827744 -4.887605 -4.524547 -3.905259 -3.582610 -3.070505 -2.613288 -1.281405 -1.743165 -3.486569 -3.897461 -4.267935 -4.541713 -4.859178 -4.756778 -4.213835 -2.847547 -2.280222 -0.963912 -1.987621 -3.603433 -3.856605 -5.088579 -4.641242 -3.634077 -4.000145 -2.793157 -1.836506 -1.585756 -0.420265 -2.177519 -4.055057 -4.769684 -5.046757 -4.519601 -3.732124 -3.115753 -2.466236 -1.607966 -0.646700 0.245146 -2.215916 -4.286207 -5.244895 -5.653705 -5.083173 -3.625354 -2.496458 -1.605531 -0.323857 0.651160 0.967474 -1.929312 -3.529077 -4.487432 -5.541132 -4.628743 -3.130496 -2.009126 -0.606574 1.511933 2.191418 1.692105 -1.489431 -2.091605 -3.167188 -4.533048 -3.349632 -2.119821 -0.311824 1.751539 3.200481 3.436142 2.307755 -1.130715 -1.627955 -1.445848 -0.941973 -1.879666 -0.702061 0.638275 2.116359 3.816855 3.986768 2.655073 -0.818955 -0.918408 -0.449507 0.253043 -0.129225 0.485119 1.331933 2.327972 3.519821 4.024046 2.735958 -0.235532 0.038909 0.459734 0.958072 1.273691 1.537809 1.853655 2.224347 2.608293 2.808483 1.844668 -0.612769 -1.388166 -1.911309 -2.424228 -2.617586 -2.549711 -2.260052 -1.966583 -1.839766 -1.756778 -1.044495 -1.264313 -2.824853 -3.867285 -4.738451 -4.535036 -4.396440 -3.629803 -3.149718 -2.755534 -2.467539 -1.313252 -1.586132 -3.157419 -4.321326 -4.786400 -2.357417 -3.123576 -4.257049 -4.020576 -2.847559 -2.289919 -1.036266 -1.847530 -2.945774 -3.497571 -5.504957 -3.030816 -1.174723 -3.034116 -3.236203 -2.169002 -1.755779 -0.528428 -2.015693 -3.423222 -4.518471 -5.228547 -3.225224 -2.169570 -2.071631 -2.406419 -1.720588 -0.870884 0.138031 -2.087623 -4.261068 -5.647076 -5.992533 -5.434349 -3.727848 -2.277015 -2.079489 -0.633569 0.455781 0.886276 -1.722086 -3.157275 -4.477779 -5.212560 -4.633282 -4.079727 -3.213396 -1.736889 0.994979 2.074499 1.650909 -1.208735 -1.151971 -3.376458 -4.879449 -2.785683 -2.505082 -0.390740 2.753890 3.189470 3.387175 2.299662 -0.958571 -1.445761 -2.237448 -0.773834 -1.598241 -1.117386 0.975700 2.833414 3.949138 3.978979 2.651100 -0.731248 -0.905575 -0.517010 0.658144 0.367954 0.990968 1.777065 2.622963 3.627077 4.017510 2.723648 -0.202940 0.002971 0.381666 0.890968 1.306432 1.658960 1.926759 2.202744 2.539287 2.726469 1.818534 -0.317319 -0.740736 -1.135360 -1.512468 -1.589277 -1.464981 -1.232670 -1.087081 -1.202082 -1.343670 -0.963223 -0.938898 -2.179041 -3.110775 -3.984749 -3.773157 -3.546907 -2.587290 -2.027085 -2.020732 -2.028277 -1.256198 -1.380211 -2.851120 -3.868502 -4.384222 -3.488354 -3.922949 -2.487145 -1.900196 -2.173388 -1.974992 -1.031799 -1.859246 -4.012263 -3.786864 -2.069472 -1.660581 -0.998042 -0.995075 -1.267368 -1.981245 -1.645436 -0.586037 -1.994273 -4.059949 -4.264480 -4.108476 -2.790025 0.112947 1.451331 -0.630425 -1.317652 -0.904034 0.041457 -1.912824 -4.181089 -5.403355 -5.364872 -4.850789 -1.497597 0.648970 -1.472495 -0.570040 0.227797 0.763078 -1.484302 -3.359623 -5.025041 -4.299769 -4.477490 -4.008573 -2.668135 -1.223545 1.038548 1.697904 1.505395 -0.978304 -1.622283 -2.581697 -3.264181 -3.995483 -2.714941 0.278043 3.032793 3.494461 3.035921 2.137858 -0.744838 -1.333267 -1.847111 -1.796722 -1.957010 0.981559 2.505437 3.212338 3.588552 3.597045 2.475561 -0.597054 -0.824375 -0.701741 -0.120103 0.581718 1.997845 2.251435 2.654554 3.339430 3.668460 2.542837 -0.156600 -0.049604 0.265078 0.700883 1.090191 1.424869 1.648556 1.891593 2.222939 2.425663 1.679623 -0.032746 -0.008610 -0.050815 0.028768 0.413131 0.698828 0.511519 0.076731 -0.435782 -0.818878 -0.825434 -0.681152 -1.480032 -1.717308 -2.095030 -0.458855 0.477825 -0.265291 -0.341253 -0.871395 -1.275796 -1.087895 -1.264148 -2.559777 -2.029119 -2.806269 -1.745753 0.155207 0.947704 0.685631 -0.797144 -1.154314 -0.884510 -1.919517 -4.647817 -3.077586 0.528159 -0.276563 0.547656 2.839989 1.014810 -1.003251 -0.905220 -0.485046 -2.048188 -4.627845 -4.292828 -2.936353 -2.353959 0.084295 2.405953 0.090685 -1.011509 -0.514405 0.070618 -1.841642 -4.054992 -4.435475 -4.093608 -3.739975 -1.254330 0.598142 -1.353499 -1.172408 0.098021 0.695669 -1.323526 -3.176215 -4.584857 -5.013717 -5.256146 -3.080522 -2.232666 -2.351568 -0.272443 1.136034 1.317669 -0.808199 -1.837746 -3.380344 -4.869953 -4.629428 -2.557595 -1.506131 -0.077356 1.557963 2.178059 1.849087 -0.585729 -1.108290 -1.491144 -1.858527 -0.683727 0.611623 -0.014655 0.420731 2.179699 2.745903 2.155244 -0.483065 -0.673672 -0.478012 -0.048005 -0.158089 -0.468238 0.388194 1.517301 2.395911 2.922174 2.232044 -0.116331 -0.095834 0.183141 0.446279 0.397918 0.329782 0.638428 1.126480 1.620837 1.937579 1.465062 0.223642 0.700578 1.052898 1.665095 2.610702 3.095890 2.353100 1.239646 0.312468 -0.301878 -0.669030 -0.395615 -0.612415 -0.164949 0.762797 3.852678 4.705745 2.132236 1.214474 0.228489 -0.512614 -0.876938 -1.033141 -1.788242 -1.112259 -1.521185 2.393703 3.324049 1.540508 1.914250 0.466582 -0.300290 -0.670364 -1.706857 -3.447394 -1.566985 0.435180 0.991424 1.988447 3.711703 2.415482 0.420195 -0.068018 -0.297427 -1.827475 -3.670368 -3.499923 -1.193996 -1.057028 0.567500 0.668689 -0.381277 -0.296560 0.028007 0.181102 -1.637768 -3.376861 -4.551112 -3.650906 -1.610284 -0.679074 -1.854283 -2.823491 -1.083496 0.234025 0.687395 -1.192156 -2.819726 -4.055109 -4.825856 -3.480310 -2.186039 -2.809719 -2.713561 -0.749630 0.817884 1.155769 -0.710318 -1.514268 -2.614092 -4.200929 -4.383476 -2.585965 -1.098894 -0.695089 0.309443 1.511160 1.555720 -0.508182 -0.991405 -2.441238 -2.365115 -1.243471 -1.725440 -0.027496 -0.176770 1.130754 1.995911 1.815310 -0.421219 -0.604474 -0.528410 0.027320 -1.113006 -3.594133 -1.432633 0.527821 1.536248 2.202998 1.896947 -0.100191 -0.157606 0.095827 0.170020 -0.391606 -0.910017 -0.478161 0.332799 1.013935 1.441083 1.233704 0.440493 1.291598 1.901119 2.786903 3.853100 4.562027 3.639166 2.132034 0.916939 0.114285 -0.512084 0.028417 0.589191 1.511940 3.210875 4.921352 6.174414 3.910014 2.075638 0.851565 -0.002883 -0.666526 -0.485124 -0.306577 0.694117 1.895776 3.312102 2.244501 1.230406 1.659235 0.785799 0.147612 -0.445726 -1.052448 -1.414317 0.159554 2.300398 1.567374 0.181211 2.254287 2.227093 0.778703 0.326499 -0.085941 -1.287231 -1.980987 -0.606762 0.617015 -0.709563 -1.338747 -0.544477 0.461130 0.330555 0.407431 0.322319 -1.272227 -2.299105 -2.210936 -1.527807 0.440469 -0.502576 -0.691581 -1.178870 -0.146197 0.604462 0.719981 -0.997088 -2.078277 -2.273296 -2.289964 -0.881573 -2.165208 -0.636683 -0.014658 0.447437 1.073699 1.055640 -0.714705 -2.102356 -2.248387 -2.409743 -3.624985 -1.440049 0.042411 0.742465 1.239999 1.565419 1.334183 -0.542242 -1.466875 -2.243486 -1.821068 -2.936228 -1.031316 0.654579 0.700359 1.470199 1.821324 1.528329 -0.432771 -0.725949 -0.511523 -0.327454 -2.405751 -4.334386 -1.742671 0.558708 1.434068 1.859837 1.590173 -0.124501 -0.258460 -0.036145 -0.089709 -1.011097 -1.734585 -1.093251 -0.085067 0.643894 1.067154 1.010035 0.602863 1.715766 2.457326 3.415534 4.320563 5.369598 4.515573 2.815570 1.408743 0.448408 -0.365064 0.450340 1.666965 2.653992 3.925567 3.870414 7.643403 6.227599 2.818110 1.360248 0.388646 -0.479355 0.123457 0.906200 1.487534 3.274179 4.203769 5.222674 3.114076 1.377018 0.837391 0.419190 -0.256502 -0.297554 0.085395 0.922426 3.000461 1.238277 -0.820008 0.044006 0.805815 0.252603 0.502490 0.081650 -0.598903 -0.163631 2.029702 3.035765 1.332057 -1.404836 0.306156 0.754303 0.264729 0.682861 0.427634 -0.760696 -0.649607 0.316570 1.249229 2.837259 -0.136213 0.667729 1.012808 0.625141 0.988631 0.737296 -0.768059 -1.327851 -1.267993 -0.848967 0.694388 -0.293893 1.752239 1.746134 1.448679 1.425632 0.972312 -0.733192 -2.712632 -3.413955 -2.771372 -2.163302 -1.177702 1.129044 1.789362 2.011630 1.764767 1.157419 -0.611419 -1.935910 -2.366046 -1.445216 -3.030355 -3.119161 0.146806 1.669290 1.908493 1.787645 1.288898 -0.482436 -0.933001 -0.609252 -0.611445 -2.178150 -4.971577 -1.940253 0.736236 1.456140 1.631884 1.323065 -0.174491 -0.396529 -0.228359 -0.334005 -1.176547 -2.136684 -1.438466 -0.345962 0.371371 0.769169 0.810449 0.683444 1.890514 2.645991 3.632684 4.515901 5.581025 4.939461 3.283482 1.785098 0.711414 -0.228470 0.717708 2.159968 3.086022 4.561131 4.073497 7.736831 7.319285 3.814960 2.065067 0.790154 -0.323913 0.536164 1.673631 2.034086 4.637815 5.086218 5.611780 4.065942 2.169181 1.548687 0.767189 -0.139050 0.263825 1.295465 2.263227 4.070812 1.452665 -1.462454 -0.423357 1.110535 0.981740 0.776322 0.139630 -0.030185 0.879146 2.488630 3.421680 2.006915 -0.490777 1.403240 1.455150 0.791323 0.897586 0.421065 -0.300624 0.017188 0.375948 1.510972 2.170577 1.724583 1.994663 1.512038 1.026263 1.117384 0.666523 -0.523685 -0.952370 -1.869302 -1.381605 1.785001 2.817045 2.537920 1.612978 1.520180 1.372124 0.842311 -0.661130 -2.194062 -3.601920 -1.717769 1.017504 1.120410 2.059681 1.744226 1.770446 1.516316 0.974458 -0.627024 -1.918858 -3.006039 -2.381409 -1.373001 -2.866614 -0.320273 1.300814 1.443177 1.425572 1.064339 -0.522242 -1.098410 -1.040203 -1.337566 -0.960747 -3.680545 -2.374207 0.184665 0.941232 1.225834 1.078701 -0.231637 -0.561346 -0.498985 -0.658054 -1.209121 -1.999392 -1.608702 -0.656255 0.051550 0.484477 0.633919 0.693956 1.878496 2.578852 3.540306 4.569342 5.509339 4.929292 3.440533 1.960395 0.857410 -0.125018 0.833029 2.257073 3.055719 4.264167 4.921061 7.491023 7.212822 4.595053 2.582522 1.061315 -0.209551 0.736496 1.982307 2.533066 3.684103 4.861003 5.638792 4.750251 3.322036 2.158861 1.018684 -0.071011 0.555499 1.630316 2.267019 2.832820 2.751127 1.669034 1.401439 1.885697 1.594032 0.971720 0.143751 0.315211 1.295424 2.192037 2.143976 1.556989 1.538044 2.183456 1.691013 1.233571 0.999206 0.369586 0.024498 0.399826 0.209540 0.953780 1.880903 3.113172 2.635884 1.473573 1.139701 1.075562 0.569874 -0.308306 -0.633749 -2.206092 -1.878606 1.484519 2.736607 1.825104 1.222651 1.181525 1.139861 0.712312 -0.554607 -1.035985 -1.674148 -2.044960 -0.105713 0.861877 1.080355 0.985127 1.129469 1.141351 0.816490 -0.597786 -1.391521 -1.397786 -1.307183 -1.312552 -1.913958 -0.773996 0.329889 0.764070 1.016674 0.880759 -0.530564 -1.153019 -1.075119 -1.245124 -1.664621 -2.536664 -2.002425 -0.443120 0.368442 0.843058 0.882714 -0.269250 -0.674339 -0.708703 -0.926119 -1.485284 -1.926656 -1.624994 -0.872736 -0.192387 0.272950 0.498315 0.467011 1.255010 1.696611 2.285097 2.939892 3.328039 2.955315 2.181431 1.349757 0.703909 0.042269 0.615696 1.600007 2.113382 2.851946 3.795493 4.582817 4.179483 3.075108 1.872275 0.923954 0.027892 0.588879 1.477987 1.859233 2.306840 3.058733 3.628314 3.389881 2.664615 1.722199 0.912299 0.084045 0.511707 1.240407 1.445575 1.632422 2.067396 2.316451 2.288751 2.040847 1.452732 0.870447 0.169803 0.389734 0.987368 1.160311 1.288297 1.489892 1.770804 1.820331 1.581567 1.192687 0.826096 0.261745 0.220085 0.601223 0.644965 0.877213 1.234795 1.586770 1.467899 1.174980 0.953092 0.769431 0.342245 -0.007111 0.028656 -0.093414 0.095106 0.714677 1.075877 0.953082 0.770834 0.710174 0.676554 0.394117 -0.209718 -0.421681 -0.444473 -0.453742 0.004576 0.360271 0.400870 0.359758 0.459845 0.563109 0.425969 -0.301785 -0.670398 -0.680371 -0.670842 -0.661681 -0.643069 -0.407336 -0.126728 0.183496 0.428986 0.435038 -0.318579 -0.715538 -0.782501 -0.896810 -1.183220 -1.307302 -1.007243 -0.508586 -0.034561 0.307293 0.418031 -0.209786 -0.535058 -0.654643 -0.837525 -1.110468 -1.254206 -1.050267 -0.669059 -0.274554 0.017938 0.212004 0.049748 0.419435 0.718493 1.076395 1.366190 1.549565 1.567561 1.482324 1.325176 1.150412 0.600856 -0.228860 0.234938 0.795976 1.451899 1.987926 2.372596 2.499584 2.462656 2.277140 2.027758 1.102760 -0.490391 -0.117447 0.533273 1.238092 1.874576 2.421591 2.648884 2.706162 2.550922 2.284871 1.258922 -0.819531 -0.654201 -0.028923 0.672720 1.396554 2.075002 2.522388 2.771527 2.708526 2.472906 1.398074 -1.111353 -1.281907 -0.913545 -0.308698 0.343473 1.044972 1.846696 2.471855 2.625372 2.487022 1.472726 -1.312064 -1.809187 -1.769732 -1.469307 -0.834196 0.043483 1.191033 2.132737 2.489399 2.420321 1.481166 -1.352957 -2.028097 -2.212618 -2.108261 -1.348206 -0.161348 1.137978 2.065108 2.434475 2.313666 1.392973 -1.288701 -1.984271 -2.225925 -2.146076 -1.286100 0.013192 1.312294 2.258537 2.426637 2.139942 1.251040 -1.149278 -1.709487 -1.819551 -1.633602 -0.850945 0.185330 1.214113 1.971675 2.046223 1.818235 1.073095 -0.991345 -1.386687 -1.338368 -1.055506 -0.429187 0.325511 1.027520 1.525747 1.611666 1.489089 0.904749 -0.516437 -0.673516 -0.569902 -0.362881 -0.075168 0.227984 0.489691 0.678226 0.748433 0.735956 0.467271 -0.089716 0.398890 0.882523 1.478203 1.974552 2.304802 2.373917 2.285770 2.097296 1.868049 1.010857 -0.669293 -0.077813 0.903082 1.916911 2.878659 3.704407 4.031194 4.058884 3.803207 3.409424 1.875722 -1.136978 -0.685628 0.534886 1.299629 2.488900 3.550689 4.183170 4.568833 4.480773 3.981739 2.161658 -1.695321 -1.595312 -0.349464 0.268338 1.705198 3.133743 4.133170 4.707648 4.737108 4.403784 2.414147 -2.151966 -2.686327 -1.922157 -1.361329 -0.368335 1.408457 3.275292 4.460187 4.576979 4.401999 2.532243 -2.443379 -3.704279 -3.867368 -3.372744 -2.495873 -0.923635 1.935232 3.789887 4.473322 4.262575 2.527872 -2.458119 -4.059897 -4.828118 -4.954578 -3.555774 -0.791823 2.058892 3.254707 4.283767 4.098048 2.363261 -2.293686 -3.830844 -4.693897 -4.774449 -2.678878 0.246329 2.768799 4.629151 4.820205 3.833798 2.111248 -2.017909 -3.200822 -3.659253 -3.361347 -1.513014 0.359541 2.448072 4.206511 3.969060 3.228069 1.802353 -1.724925 -2.511326 -2.532523 -2.049172 -0.696001 0.840999 2.177912 3.054176 2.993384 2.600952 1.513530 -0.894064 -1.188904 -1.025800 -0.665013 -0.119683 0.452705 0.913165 1.215193 1.293134 1.234899 0.773954 -0.217479 0.204202 0.688141 1.314911 1.888309 2.299753 2.416065 2.359642 2.205110 1.997623 1.106599 -0.937569 -0.528128 0.428744 1.581239 2.720485 3.643160 4.147854 4.310290 4.103514 3.701572 2.061982 -1.476718 -1.283608 -0.124566 1.021812 2.806310 3.149146 3.865264 4.821073 4.928232 4.391531 2.383861 -2.096926 -2.282514 -1.047794 -0.120556 2.485116 2.012992 3.396832 5.599916 5.276251 4.898836 2.663335 -2.619317 -3.687647 -2.792795 -2.387913 -0.204861 1.330678 4.020953 6.346083 5.261842 4.868238 2.778206 -2.906149 -4.647853 -5.111920 -4.455228 -3.281235 -1.387702 2.390005 4.919047 5.072222 4.638256 2.756089 -2.847522 -4.547965 -5.757889 -5.364323 -3.519724 -0.539611 3.071175 4.613206 4.842903 4.376623 2.570096 -2.616471 -4.108824 -5.211540 -4.622089 -1.632291 1.236287 3.618455 5.754635 5.231455 4.071235 2.296283 -2.307968 -3.644089 -4.130314 -3.414579 -0.902847 0.675809 2.471595 4.736433 4.282115 3.443054 1.963780 -1.959598 -2.855341 -2.825620 -2.139117 -0.511632 1.079944 2.400342 3.283707 3.197763 2.797048 1.652762 -1.010014 -1.354841 -1.167258 -0.751885 -0.126749 0.509961 0.988695 1.291990 1.378672 1.327629 0.843069 -0.371111 -0.061254 0.394690 1.035137 1.703124 2.220295 2.388315 2.361246 2.246611 2.070080 1.176216 -1.222158 -1.098171 -0.300699 0.900493 2.273528 3.421840 4.132904 4.417454 4.253175 3.868921 2.196464 -1.806241 -2.006934 -1.198706 0.000846 2.183082 3.203923 4.539042 5.389976 5.225102 4.624225 2.541083 -2.488175 -3.276343 -2.637964 -1.566576 1.167236 0.982457 3.759598 6.433238 5.866615 5.189275 2.836225 -3.048177 -4.900142 -4.957327 -4.185174 -1.193194 -0.395877 3.854585 7.287173 5.707075 5.110181 2.946438 -3.298121 -5.488277 -6.372268 -6.264233 -4.348463 -1.133185 2.942116 5.136290 5.157326 4.803848 2.912589 -3.200797 -5.273294 -6.879461 -6.807765 -4.075449 -0.164130 3.507828 3.834836 4.660416 4.494362 2.717679 -2.923895 -4.710465 -5.727235 -5.679040 -3.054287 1.034394 4.506826 5.653218 5.395816 4.155696 2.435495 -2.544728 -3.995582 -4.344078 -3.712043 -1.102959 1.052345 3.348569 4.785479 4.391127 3.528258 2.089060 -2.143967 -3.141106 -3.117377 -2.391405 -0.518300 1.149224 2.555377 3.237722 3.216108 2.890852 1.762307 -1.099283 -1.494786 -1.301304 -0.866260 -0.199137 0.475386 0.968309 1.279995 1.398995 1.378611 0.896461 -0.493096 -0.299761 0.110928 0.753447 1.544408 2.170762 2.356661 2.325901 2.226226 2.067957 1.196949 -1.396108 -1.574686 -1.074730 -0.045872 1.802124 3.345426 4.033065 4.289098 4.158979 3.825110 2.228619 -1.949041 -2.554488 -2.261056 -1.520488 0.838296 2.606553 4.332824 5.426756 5.085378 4.501810 2.565631 -2.575811 -3.692400 -3.588225 -3.027413 -0.914517 0.704988 3.587753 6.276349 5.862716 5.020887 2.854292 -3.059731 -4.761279 -5.380168 -5.129592 -3.182107 -1.335114 2.566174 5.746091 5.606835 4.997912 2.969590 -3.341724 -5.496556 -6.213168 -6.368005 -3.702872 -0.887515 2.266250 4.273510 4.949409 4.756105 2.949397 -3.287375 -5.574579 -6.574233 -6.877793 -5.062638 -0.398839 3.518994 3.635585 4.132663 4.434110 2.772718 -3.017799 -5.127667 -5.602769 -5.583043 -4.745754 -0.590816 3.980458 4.145556 4.360419 4.059781 2.504237 -2.597712 -4.136725 -4.355734 -3.786102 -2.042570 0.142738 2.996605 3.673333 3.872048 3.459583 2.155875 -2.177539 -3.248186 -3.302929 -2.847459 -1.290795 0.389657 2.088432 2.805122 2.993435 2.845606 1.820047 -1.113665 -1.546538 -1.389947 -1.007207 -0.394703 0.248045 0.771869 1.137417 1.330352 1.371298 0.923130 -0.536804 -0.419106 -0.055056 0.578161 1.505580 2.140372 2.288411 2.251399 2.154740 2.003680 1.170951 -1.406481 -1.769362 -1.499039 -0.406831 2.580075 3.933722 4.082810 4.132090 3.990895 3.674320 2.175813 -1.890828 -2.762742 -2.907532 -2.236766 1.053594 3.283904 4.431133 4.923498 4.747126 4.253516 2.491851 -2.435444 -3.872842 -4.312304 -3.637009 -1.427541 1.212481 3.681938 5.083674 5.162556 4.722950 2.767340 -2.821886 -4.335195 -5.011207 -4.325978 -2.412607 0.034077 3.253013 4.926909 4.831400 4.805356 2.897778 -3.027159 -4.456540 -5.505858 -5.641859 -2.965363 -0.317741 3.270968 5.181041 4.756361 4.676992 2.905669 -3.065779 -5.213332 -6.155731 -6.510516 -5.146471 -0.907961 4.031220 4.810337 4.528717 4.409639 2.756330 -2.831978 -4.943596 -5.637588 -5.374904 -4.442330 -1.247510 2.253563 3.294508 4.122880 4.021051 2.508369 -2.429001 -3.992760 -4.280544 -3.597693 -2.347735 -0.181221 1.115823 2.609794 3.588240 3.408169 2.167762 -2.025664 -3.089675 -3.170740 -2.686138 -1.551812 -0.030229 1.540639 2.456110 2.834150 2.791233 1.832354 -1.030792 -1.452663 -1.342418 -1.028915 -0.499026 0.065296 0.608755 1.025409 1.271784 1.353155 0.928215 -0.448296 -0.326869 -0.004994 0.549885 1.295866 1.868547 2.093035 2.088864 1.998186 1.848133 1.076721 -1.176395 -1.476704 -1.279158 -0.132601 2.084539 3.647810 4.358448 4.115335 3.837197 3.441123 2.010772 -1.581747 -2.349890 -2.664303 -1.830484 1.214236 4.617426 5.335551 4.856612 4.661846 4.012781 2.301975 -2.039950 -3.380976 -4.197653 -4.243074 -0.732901 3.251230 4.568379 5.111849 5.221021 4.522907 2.566465 -2.373375 -3.909113 -5.066434 -4.576359 -2.231061 2.125921 6.287624 6.581273 5.180840 4.730694 2.720224 -2.548348 -4.177170 -5.850526 -5.136256 -3.676744 -0.311799 5.542769 7.041854 5.497538 4.737159 2.761239 -2.529185 -4.450587 -5.835488 -5.901637 -3.890674 -1.841160 4.680191 6.152408 5.408753 4.537601 2.634015 -2.318208 -4.227191 -5.288321 -5.036940 -2.501422 0.247333 3.090113 4.842286 4.958963 4.124024 2.403673 -1.960572 -3.310003 -3.746652 -3.367378 -1.608645 0.609151 1.563958 3.403395 3.938265 3.453285 2.085644 -1.612569 -2.499313 -2.642790 -2.354122 -1.281059 0.114452 1.615175 2.733120 2.960170 2.792753 1.770032 -0.807153 -1.126819 -1.046970 -0.804617 -0.359458 0.134256 0.655879 1.073721 1.290596 1.342471 0.898932 -0.283701 -0.142931 0.089000 0.469127 0.981554 1.403050 1.689469 1.817434 1.774456 1.640354 0.949109 -0.810059 -1.010808 -0.927140 -0.142482 1.301197 2.392530 3.472879 3.792240 3.535076 3.125835 1.799072 -1.127506 -1.599321 -1.572251 -0.795999 1.062208 4.012689 5.347851 5.009284 4.431466 3.704338 2.074303 -1.488005 -2.421343 -3.199154 -4.203117 -0.449466 5.384197 6.254789 5.819242 5.315369 4.267581 2.338125 -1.764135 -3.238820 -4.947662 -5.894769 -2.083252 5.155914 7.780767 6.786109 5.756089 4.602885 2.517921 -1.911817 -3.636016 -5.761828 -5.654331 -2.164929 3.533333 7.994212 6.866953 5.937123 4.721372 2.588145 -1.844814 -3.620930 -5.271803 -5.094943 -1.321507 3.104639 8.254280 6.887345 5.773770 4.550052 2.474465 -1.652588 -3.428682 -4.640826 -3.903928 -0.941072 3.264080 6.169758 6.046210 5.276422 4.138389 2.255077 -1.354202 -2.541567 -3.394695 -3.190854 -1.089799 1.888197 3.766007 4.435356 4.181119 3.452808 1.961164 -1.076272 -1.731665 -2.011345 -1.932872 -0.977837 0.457278 2.195111 3.071020 3.092942 2.775086 1.670651 -0.514805 -0.689783 -0.634746 -0.462358 -0.160192 0.255800 0.791042 1.176018 1.331670 1.328454 0.851021 -0.091912 0.021487 0.069100 0.160037 0.362932 0.630695 1.025214 1.389528 1.468536 1.386235 0.802692 -0.392236 -0.663086 -0.990935 -1.150578 -0.542365 0.035077 1.287792 2.663414 2.861594 2.665268 1.566808 -0.614543 -1.286768 -1.871012 -2.248683 -1.105201 0.378347 1.685764 3.536869 3.564881 3.177895 1.840801 -0.870433 -1.993258 -3.249727 -4.553027 -1.167992 2.873946 3.634568 4.615801 4.323375 3.705098 2.115705 -1.064133 -2.477320 -4.133569 -5.466805 -2.376642 2.252279 4.227995 5.069986 4.891015 4.081205 2.313827 -1.176266 -2.971224 -4.500560 -4.782411 -1.332013 2.646557 4.486676 5.189901 5.181827 4.261871 2.398956 -1.131950 -3.123898 -4.378001 -3.474090 -0.087194 4.624906 6.749120 5.688949 5.095494 4.137191 2.291175 -0.966012 -2.481141 -3.856991 -3.502122 0.324525 4.130549 3.909829 4.864778 4.705740 3.786568 2.077913 -0.736014 -1.769941 -2.924041 -3.201440 -1.544344 0.999678 3.067936 4.068218 3.808970 3.196618 1.803387 -0.528002 -0.985398 -1.375272 -1.534710 -0.879811 0.458988 2.037422 2.862908 2.899306 2.605095 1.535813 -0.213028 -0.243254 -0.215002 -0.110709 0.109049 0.449205 0.870290 1.205454 1.313373 1.272886 0.782170 0.060899 0.141337 0.030252 -0.099165 -0.209636 -0.073401 0.461569 1.004443 1.185658 1.151531 0.668606 -0.057652 -0.410784 -1.140801 -1.810832 -2.227909 -2.208444 -0.486110 1.564793 2.183401 2.214222 1.348179 -0.199861 -0.980244 -2.133652 -3.359157 -3.549678 -3.642337 -1.937603 1.803536 2.634904 2.640548 1.617960 -0.372064 -1.614718 -3.151504 -4.707835 -4.382800 -3.937953 -2.573019 2.124566 3.148924 3.094896 1.896328 -0.503302 -1.999434 -3.883442 -4.895219 -4.097261 -4.320874 -2.441948 2.564763 3.620043 3.455429 2.098779 -0.573017 -2.139788 -3.539681 -4.442266 -3.660222 -4.081765 -1.929920 2.952590 3.971742 3.660711 2.187298 -0.543201 -2.047933 -3.155706 -3.814734 -3.121295 -3.996468 -0.782194 3.606076 4.053358 3.583569 2.085171 -0.431269 -1.557509 -2.614320 -3.926400 -3.088331 -3.837877 -1.778225 3.236314 3.839744 3.305194 1.881897 -0.259154 -1.020595 -2.023074 -3.202912 -4.098538 -4.121685 0.024327 3.076836 3.228482 2.838130 1.628063 -0.107965 -0.405280 -0.861909 -1.291647 -1.875783 -1.003257 1.305344 2.455176 2.574221 2.360890 1.384023 0.016663 0.095512 0.106017 0.152318 0.248554 0.521834 0.884381 1.175254 1.247126 1.185337 0.704066 0.202573 0.312007 0.217513 0.079255 -0.052277 -0.038873 0.234401 0.531221 0.614806 0.579508 0.317779 0.308947 0.240662 -0.243369 -0.819160 -1.266584 -1.277126 -0.376194 0.669116 1.070733 1.117975 0.669264 0.308262 0.045137 -0.686386 -1.521473 -2.011001 -2.048342 -0.938490 0.639362 1.225687 1.335258 0.825700 0.296668 -0.165954 -1.121055 -2.166199 -2.667236 -2.598782 -1.354261 0.656517 1.419964 1.576581 0.993125 0.286737 -0.259230 -1.312450 -2.270161 -2.597752 -2.492599 -1.130505 0.915822 1.657109 1.789107 1.119365 0.284908 -0.250705 -1.194377 -2.036751 -2.141234 -1.943281 -0.517081 1.281009 1.877161 1.928602 1.181288 0.291155 -0.206665 -1.072106 -1.800181 -1.697675 -1.475249 0.062023 1.628875 1.990766 1.919314 1.135799 0.313752 -0.062487 -0.765917 -1.399235 -1.292149 -0.914774 0.447861 1.784216 1.977434 1.806497 1.031910 0.353384 0.218661 -0.253186 -0.697181 -0.806310 -0.371761 0.897724 1.726033 1.776938 1.598443 0.897398 0.377370 0.478228 0.275634 0.092707 -0.003668 0.391976 1.125651 1.512980 1.520047 1.372661 0.765857 0.250486 0.447407 0.478540 0.511134 0.549613 0.639618 0.760806 0.836831 0.804571 0.720616 0.393582) 4 | (InitialTransformParametersFileName "NoInitialTransform") 5 | (HowToCombineTransforms "Compose") 6 | 7 | // Image specific 8 | (FixedImageDimension 3) 9 | (MovingImageDimension 3) 10 | (FixedInternalImagePixelType "float") 11 | (MovingInternalImagePixelType "float") 12 | (Size 128 128 128) 13 | (Index 0 0 0) 14 | (Spacing 1.0000000000 1.0000000000 1.0000000000) 15 | (Origin 0.0000000000 0.0000000000 0.0000000000) 16 | (Direction 1.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000) 17 | (UseDirectionCosines "true") 18 | 19 | // BSplineTransform specific 20 | (GridSize 11 11 11) 21 | (GridIndex 0 0 0) 22 | (GridSpacing 16.0000000000 16.0000000000 16.0000000000) 23 | (GridOrigin -16.5000000000 -16.5000000000 -16.5000000000) 24 | (GridDirection 1.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000) 25 | (BSplineTransformSplineOrder 3) 26 | (UseCyclicTransform "false") 27 | 28 | // ResampleInterpolator specific 29 | (ResampleInterpolator "FinalBSplineInterpolator") 30 | (FinalBSplineInterpolationOrder 0) 31 | 32 | // Resampler specific 33 | (Resampler "DefaultResampler") 34 | (DefaultPixelValue 0.000000) 35 | (ResultImageFormat "mhd") 36 | (ResultImagePixelType "char") 37 | (CompressResultImage "false") 38 | -------------------------------------------------------------------------------- /regFiles/parameters_BSpline.txt: -------------------------------------------------------------------------------- 1 | // Example parameter file for B-spline registration 2 | // C-style comments: // 3 | 4 | // The internal pixel type, used for internal computations 5 | // Leave to float in general. 6 | // NB: this is not the type of the input images! The pixel 7 | // type of the input images is automatically read from the 8 | // images themselves. 9 | // This setting can be changed to "short" to save some memory 10 | // in case of very large 3D images. 11 | (FixedInternalImagePixelType "float") 12 | (MovingInternalImagePixelType "float") 13 | 14 | // The dimensions of the fixed and moving image 15 | // Up to elastix 4.5 this had to be specified by the user. 16 | // From elastix 4.6, this is not necessary anymore. 17 | //(FixedImageDimension 2) 18 | //(MovingImageDimension 2) 19 | 20 | // Specify whether you want to take into account the so-called 21 | // direction cosines of the images. Recommended: true. 22 | // In some cases, the direction cosines of the image are corrupt, 23 | // due to image format conversions for example. In that case, you 24 | // may want to set this option to "false". 25 | (UseDirectionCosines "true") 26 | 27 | // **************** Main Components ************************** 28 | 29 | // The following components should usually be left as they are: 30 | (Registration "MultiResolutionRegistration") 31 | (Interpolator "BSplineInterpolator") 32 | (ResampleInterpolator "FinalBSplineInterpolator") 33 | (Resampler "DefaultResampler") 34 | 35 | // These may be changed to Fixed/MovingSmoothingImagePyramid. 36 | // See the manual. 37 | (FixedImagePyramid "FixedRecursiveImagePyramid") 38 | (MovingImagePyramid "MovingRecursiveImagePyramid") 39 | 40 | // The following components are most important: 41 | // The optimizer AdaptiveStochasticGradientDescent (ASGD) works 42 | // quite ok in general. The Transform and Metric are important 43 | // and need to be chosen careful for each application. See manual. 44 | (Optimizer "AdaptiveStochasticGradientDescent") 45 | (Transform "BSplineTransform") 46 | (Metric "AdvancedMattesMutualInformation") 47 | 48 | // ***************** Transformation ************************** 49 | 50 | // The control point spacing of the bspline transformation in 51 | // the finest resolution level. Can be specified for each 52 | // dimension differently. Unit: mm. 53 | // The lower this value, the more flexible the deformation. 54 | // Low values may improve the accuracy, but may also cause 55 | // unrealistic deformations. This is a very important setting! 56 | // We recommend tuning it for every specific application. It is 57 | // difficult to come up with a good 'default' value. 58 | (FinalGridSpacingInPhysicalUnits 16) 59 | 60 | // Alternatively, the grid spacing can be specified in voxel units. 61 | // To do that, uncomment the following line and comment/remove 62 | // the FinalGridSpacingInPhysicalUnits definition. 63 | //(FinalGridSpacingInVoxels 16) 64 | 65 | // By default the grid spacing is halved after every resolution, 66 | // such that the final grid spacing is obtained in the last 67 | // resolution level. You can also specify your own schedule, 68 | // if you uncomment the following line: 69 | //(GridSpacingSchedule 4.0 4.0 2.0 1.0) 70 | // This setting can also be supplied per dimension. 71 | 72 | // Whether transforms are combined by composition or by addition. 73 | // In generally, Compose is the best option in most cases. 74 | // It does not influence the results very much. 75 | (HowToCombineTransforms "Compose") 76 | 77 | // ******************* Similarity measure ********************* 78 | 79 | // Number of grey level bins in each resolution level, 80 | // for the mutual information. 16 or 32 usually works fine. 81 | // You could also employ a hierarchical strategy: 82 | //(NumberOfHistogramBins 16 32 64) 83 | (NumberOfHistogramBins 16) 84 | 85 | // If you use a mask, this option is important. 86 | // If the mask serves as region of interest, set it to false. 87 | // If the mask indicates which pixels are valid, then set it to true. 88 | // If you do not use a mask, the option doesn't matter. 89 | (ErodeMask "false") 90 | 91 | // ******************** Multiresolution ********************** 92 | 93 | // The number of resolutions. 1 Is only enough if the expected 94 | // deformations are small. 3 or 4 mostly works fine. For large 95 | // images and large deformations, 5 or 6 may even be useful. 96 | (NumberOfResolutions 3) 97 | 98 | // The downsampling/blurring factors for the image pyramids. 99 | // By default, the images are downsampled by a factor of 2 100 | // compared to the next resolution. 101 | // So, in 2D, with 4 resolutions, the following schedule is used: 102 | //(ImagePyramidSchedule 8 8 4 4 2 2 1 1 ) 103 | // And in 3D: 104 | //(ImagePyramidSchedule 8 8 8 4 4 4 2 2 2 1 1 1 ) 105 | // You can specify any schedule, for example: 106 | //(ImagePyramidSchedule 4 4 4 3 2 1 1 1 ) 107 | // Make sure that the number of elements equals the number 108 | // of resolutions times the image dimension. 109 | 110 | // ******************* Optimizer **************************** 111 | 112 | // Maximum number of iterations in each resolution level: 113 | // 200-2000 works usually fine for nonrigid registration. 114 | // The more, the better, but the longer computation time. 115 | // This is an important parameter! 116 | (MaximumNumberOfIterations 100) 117 | 118 | // The step size of the optimizer, in mm. By default the voxel size is used. 119 | // which usually works well. In case of unusual high-resolution images 120 | // (eg histology) it is necessary to increase this value a bit, to the size 121 | // of the "smallest visible structure" in the image: 122 | //(MaximumStepLength 1.0) 123 | 124 | // **************** Image sampling ********************** 125 | 126 | // Number of spatial samples used to compute the mutual 127 | // information (and its derivative) in each iteration. 128 | // With an AdaptiveStochasticGradientDescent optimizer, 129 | // in combination with the two options below, around 2000 130 | // samples may already suffice. 131 | (NumberOfSpatialSamples 2048) 132 | 133 | // Refresh these spatial samples in every iteration, and select 134 | // them randomly. See the manual for information on other sampling 135 | // strategies. 136 | (NewSamplesEveryIteration "true") 137 | (ImageSampler "Random") 138 | 139 | // ************* Interpolation and Resampling **************** 140 | 141 | // Order of B-Spline interpolation used during registration/optimisation. 142 | // It may improve accuracy if you set this to 3. Never use 0. 143 | // An order of 1 gives linear interpolation. This is in most 144 | // applications a good choice. 145 | (BSplineInterpolationOrder 1) 146 | 147 | // Order of B-Spline interpolation used for applying the final 148 | // deformation. 149 | // 3 gives good accuracy; recommended in most cases. 150 | // 1 gives worse accuracy (linear interpolation) 151 | // 0 gives worst accuracy, but is appropriate for binary images 152 | // (masks, segmentations); equivalent to nearest neighbor interpolation. 153 | (FinalBSplineInterpolationOrder 3) 154 | 155 | //Default pixel value for pixels that come from outside the picture: 156 | (DefaultPixelValue 0) 157 | 158 | // Choose whether to generate the deformed moving image. 159 | // You can save some time by setting this to false, if you are 160 | // not interested in the final deformed moving image, but only 161 | // want to analyze the deformation field for example. 162 | (WriteResultImage "true") 163 | 164 | // The pixel type and format of the resulting deformed moving image 165 | (ResultImagePixelType "char") 166 | (ResultImageFormat "mhd") 167 | 168 | 169 | -------------------------------------------------------------------------------- /regsegm_logging.py: -------------------------------------------------------------------------------- 1 | import time 2 | import datetime 3 | 4 | 5 | def logmess(out_dir, str=None): 6 | logfile = 'ctregsegm_py.log' 7 | 8 | ts = time.time() 9 | st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') 10 | 11 | if str is None: 12 | with open(out_dir + '/' + logfile, 'w') as f: 13 | f.write('\n==================================================\n') 14 | str = 'CT_RegSegm v1.0 started' 15 | 16 | str = str.replace('\\', '/') 17 | 18 | with open(out_dir + '/' + logfile, 'a') as f: 19 | print(str) 20 | f.write(st + ' -- ' + str + '\n') 21 | -------------------------------------------------------------------------------- /regsegm_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import nibabel as nb 4 | from skimage import measure, transform 5 | from scipy.ndimage.morphology import binary_dilation 6 | 7 | from regsegm_logging import logmess 8 | 9 | 10 | def imresize(m, new_shape, order=1, mode='constant'): 11 | data_type = m.dtype 12 | 13 | multiplier = np.max(np.abs(m)) * 2 14 | m = m.astype(np.float32) / multiplier 15 | m = transform.resize(m, new_shape, order=order, mode=mode) 16 | m = m * multiplier 17 | 18 | return m.astype(dtype=data_type) 19 | 20 | 21 | def write_mhd(filename, im, data_type): 22 | with open(filename + '.mhd', 'w') as f: 23 | f.write('ObjectType = Image\nNDims = %i\nBinaryData = True\n' % len(im.shape)) 24 | 25 | s = ' '.join([str(i) for i in im.shape]) 26 | f.write('BinaryDataByteOrderMSB = False\nDimSize = %s\n' % s) 27 | 28 | fn = filename.split('/')[-1] + '.raw' 29 | f.write('ElementType = MET_%s\nElementDataFile = %s' % (data_type.upper(), fn)) 30 | 31 | im = np.swapaxes(im, 0, 2).copy() 32 | im.tofile(filename + '.raw') 33 | 34 | 35 | def read_mhd_simple(filename, shape): 36 | arr = np.fromfile(filename + '.raw', dtype=np.uint8) 37 | arr = np.reshape(arr, shape[::-1]) 38 | im = np.swapaxes(arr, 0, 2).copy() 39 | return im 40 | 41 | 42 | def change_transform_parameters_file(old_file, new_file): 43 | with open(old_file, 'rt') as f1: 44 | lines = f1.readlines() 45 | 46 | to_find = '(FinalBSplineInterpolationOrder' 47 | with open(new_file, 'wt') as f2: 48 | for line in lines: 49 | if to_find in line: 50 | line = to_find + ' 0)\n' 51 | f2.write(line) 52 | 53 | 54 | def register3d(mov, fxd, moving_mask, out_dir): 55 | write_mhd(out_dir + '/moving', mov, 'char') 56 | write_mhd(out_dir + '/fixed', fxd, 'char') 57 | 58 | cmd = 'elastix -f {0}/fixed.mhd -m {0}/moving.mhd -out {0} -p {0}/parameters_BSpline.txt'.format(out_dir) 59 | logmess(out_dir, cmd) 60 | os.system(cmd) 61 | 62 | change_transform_parameters_file(out_dir + '/TransformParameters.0.txt', out_dir + '/FinalTransformParameters.txt') 63 | 64 | write_mhd(out_dir + '/mask_moving', moving_mask, 'char') 65 | cmd = 'transformix -in {0}/mask_moving.mhd -out {0} -tp {0}/FinalTransformParameters.txt'.format(out_dir) 66 | logmess(out_dir, cmd) 67 | os.system(cmd) 68 | 69 | moved_mask = read_mhd_simple(out_dir + '/result', mov.shape) 70 | 71 | return moved_mask 72 | 73 | 74 | def adv_analyze_nii_read(fn, swap_x=False, swap_y=False): 75 | img = nb.load(fn) 76 | afn = img.affine 77 | img = img.get_data() + 1024 78 | img = np.swapaxes(img, 0, 1) 79 | if not swap_x: 80 | img = img[:, ::-1] 81 | if swap_y: 82 | img = img[::-1] 83 | voxel_dimensions = np.abs(np.diag(afn[:3, :3])) 84 | shape0 = img.shape 85 | 86 | if voxel_dimensions[2] < 1.5: 87 | img = img[..., ::2].copy() 88 | voxel_dimensions[2] *= 2 89 | elif voxel_dimensions[2] > 3: 90 | new_size = (img.shape[0], img.shape[1], img.shape[2] * 2) 91 | img = imresize(img, new_size, order=0) 92 | voxel_dimensions[2] /= 2 93 | 94 | return img, voxel_dimensions, afn, shape0 95 | 96 | 97 | def save_as_nii(img, affine, out_path, swap_x=False, swap_y=False): 98 | img = img.astype(np.int16) 99 | if not swap_x: 100 | img = img[:, ::-1] 101 | if swap_y: 102 | img = img[::-1] 103 | img = np.swapaxes(img, 0, 1) 104 | 105 | affine = np.abs(affine) * np.eye(4, 4) 106 | affine[1, 1] = -affine[1, 1] 107 | affine[0, 0] = -affine[0, 0] 108 | nii = nb.Nifti1Image(img, affine) 109 | nb.save(nii, out_path) 110 | 111 | 112 | def catch_lungs(im3, voxel_dimensions): 113 | d3 = int(round(2.5 / voxel_dimensions[2])) 114 | sml = im3[::4, ::4, ::d3] 115 | sbw = sml > 700 116 | se = np.ones((3, 3, 3), dtype=bool) 117 | sbw = binary_dilation(sbw, se) 118 | 119 | sbw = np.invert(sbw).astype(int) 120 | lbl = measure.label(sbw) 121 | num_labels = np.max(lbl) 122 | for i in range(2): 123 | for j in range(2): 124 | for k in range(2): 125 | s = lbl.shape 126 | l = lbl[i * (s[0] - 1), j * (s[1] - 1), k * (s[2] - 1)] 127 | lbl[lbl == l] = 0 128 | 129 | for i in range(num_labels): 130 | if np.sum(lbl == i) < 100: 131 | lbl[lbl == i] = 0 132 | 133 | lung = lbl[::2, ::2, ::2] > 0 134 | return lung 135 | 136 | 137 | def trim_projection(projection): 138 | cumsum = np.cumsum(projection.astype(np.float) / np.sum(projection)) 139 | 140 | d = 3 141 | i1 = np.where(cumsum > 0.01)[0][0] - d 142 | i2 = np.where(cumsum < 0.99)[0][-1] + d 143 | bounds = (max((0, i1)), min((len(projection), i2 + 2))) 144 | projection = projection[bounds[0]:bounds[1]] 145 | 146 | projection = np.asarray([projection]) 147 | projection = imresize(projection, (1, 100)) 148 | projection = projection.astype(np.float32) / projection.sum() 149 | 150 | return projection, np.asarray(bounds) 151 | 152 | 153 | def calculate_lung_projections(lung, voxel_dimensions): 154 | x_proj = np.sum(lung, axis=(0, 2)).flatten() 155 | y_proj = np.sum(lung, axis=(1, 2)).flatten() 156 | z_proj = np.sum(lung, axis=(0, 1)).flatten() 157 | 158 | x_proj, xb = trim_projection(x_proj) 159 | y_proj, yb = trim_projection(y_proj) 160 | z_proj, zb = trim_projection(z_proj) 161 | 162 | projections = np.append(x_proj, (y_proj, z_proj)) 163 | projections[projections < 0] = 0 164 | d3 = int(round(2.5 / voxel_dimensions[2])) 165 | mlt = (8, 8, (2 * d3)) 166 | 167 | xyz_bounds = np.append(xb * mlt[0], (yb * mlt[1], zb * mlt[2])) 168 | 169 | projections = np.asarray([projections]) 170 | return projections, xyz_bounds 171 | 172 | 173 | def make_uint8(im): 174 | im = im * 0.17 175 | im[im < 0] = 0 176 | im[im > 255] = 255 177 | im = im.astype(np.uint8) 178 | 179 | return im 180 | -------------------------------------------------------------------------------- /resized_data/.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | *.npz 3 | -------------------------------------------------------------------------------- /result1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skliff13/CT_RegSegm/32956deeb5a541524e0e86adda8b8f3488c11ad5/result1.gif -------------------------------------------------------------------------------- /result2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skliff13/CT_RegSegm/32956deeb5a541524e0e86adda8b8f3488c11ad5/result2.gif -------------------------------------------------------------------------------- /run_regsegm.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from ct_reg_segmentor import CtRegSegmentor 4 | 5 | 6 | if __name__ == '__main__': 7 | if len(sys.argv) != 2: 8 | print('\nUsage:\tpython3 %s path/to/image/or/directory\n\n' % os.path.split(__file__)[-1]) 9 | exit(1) 10 | 11 | rs = CtRegSegmentor() 12 | 13 | path = sys.argv[1] 14 | 15 | if os.path.isdir(path): 16 | print('Processing directory ' + path + '\n') 17 | 18 | rs.process_dir(path) 19 | elif os.path.isfile(path): 20 | if path.lower().endswith('.nii.gz'): 21 | print('Processing file ' + path + '\n') 22 | 23 | rs.process_file(path) 24 | else: 25 | print('\nOnly .NII.GZ files are supported\n') 26 | else: 27 | print('File or directory not found: ' + path) 28 | exit(2) 29 | -------------------------------------------------------------------------------- /test_data/.gitignore: -------------------------------------------------------------------------------- 1 | *.nii.gz 2 | -------------------------------------------------------------------------------- /test_data/dir_with_images/.gitignore: -------------------------------------------------------------------------------- 1 | *.nii.gz 2 | --------------------------------------------------------------------------------