From a92a4d03f8c4b9a6365ee10b2e7d61ed5a78ff32 Mon Sep 17 00:00:00 2001 From: James Avery Date: Thu, 19 May 2022 15:24:10 +0200 Subject: [PATCH] CC implant segmentation Simple implementation of largest-connected-component implant segmenting. #6 TODO: Hierarchical CC to get to full resolution. --- src/segmentation/segment-implant-cc.py | 51 ++++++++++++-------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/segmentation/segment-implant-cc.py b/src/segmentation/segment-implant-cc.py index 3284d55..891cb88 100644 --- a/src/segmentation/segment-implant-cc.py +++ b/src/segmentation/segment-implant-cc.py @@ -1,4 +1,4 @@ -import h5py, sys, os.path, pathlib, numpy as np, scipy.ndimage as ndi +import h5py, sys, os.path, pathlib, numpy as np, scipy.ndimage as ndi, tqdm sys.path.append(sys.path[0]+"/../") from config.constants import * from config.paths import hdf5_root, binary_root, commandline_args @@ -8,47 +8,44 @@ NA = np.newaxis -sample, scale, chunk_size, pa_scale = commandline_args({"sample":"","scale":1,'chunk_size':256,"pa_scale":8}) +sample, scale, chunk_size = commandline_args({"sample":"","scale":8, "chunk_size":256}) # Load metadata. TODO: Clean up, make automatic function. meta_filename = f"{hdf5_root}/hdf5-byte/msb/{sample}.h5" h5meta = h5py.File(meta_filename,'r') vm_shifts = h5meta['volume_matching_shifts'] full_Nz, Ny, Nx = h5meta['voxels'].shape # Full image resolution -Nz = full_Nz - np.sum(vm_shifts) -nz,ny,nx = np.array([Nz,Ny,Nx])//pa_scale # Coarse image resolution for PA-analysis +Nz = full_Nz - np.sum(vm_shifts) # Full volume matched image resolution +nz,ny,nx = np.array([Nz,Ny,Nx])//scale # Volume matched image resolution at chosen scale voxelsize = h5meta['voxels'].attrs['voxelsize'] * scale global_vmin = np.min(h5meta['subvolume_range'][:,0]) global_vmax = np.max(h5meta['subvolume_range'][:,1]) values = np.linspace(global_vmin,global_vmax,2**16) +implant_threshold_u16 = np.argmin(np.abs(values-implant_threshold)) +print(f"Implant threshold {implant_threshold} -> {implant_threshold_u16} as uint16") h5meta.close() output_dir = f"{binary_root}/masks/implant/{scale}x" pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True) -pa_voxels = np.fromfile(f"{binary_root}/voxels/{pa_scale}x/{sample}.uint16",count=nz*ny*nx*2, offset=0, dtype=np.uint16).reshape(nz,ny,nx) -implant_threshold_u16 = np.argmin(np.abs(values-implant_threshold)) - -print(f"Implant threshold {implant_threshold} -> {implant_threshold_u16} as uint16") -pa_noisy_implant = pa_voxels > implant_threshold_u16 +noisy_implant = np.empty((nz,ny,nx),dtype=bool) +voxel_chunk = np.empty((chunk_size,ny,nx),dtype=np.uint16) -pa_label, n_features = ndi.label(pa_noisy_implant) -pa_bincnts = np.bincount(pa_label[pa_label>0],minlength=n_features+1) -largest_cc_ix = np.argmin(pa_bincnts) - -implant_mask=(pa_label==largest_cc_ix) -np.savez_compressed(f"{output_dir}/{sample}.npz",implant_mask=implant_mask) -# for z0 in range(0,Nz,chunk_size): -# z1 = min(Nz,z0+chunk_size) -# print(f"Reading and thresholding chunk {z0}:{z1} of {voxels_in.shape} {voxels_in.dtype}.") -# implant_chunk = voxels_in[z0:z1] >= byte_implant_threshold -# print(f"Max inddata: {voxels_in[z0:z1].max()}; Number of matching voxels: {np.sum(implant_chunk)}") -# if(sphere_diameter>1): -# print(f"Binary opening with {sphere_diameter*voxelsize} micrometer sphere ({sphere_diameter} voxel radius).") -# implant_chunk[sphere_diameter//2:-sphere_diameter//2] = ndi.binary_opening(implant_chunk,sph5)[sphere_diameter//2:-sphere_diameter//2] -# print("Writing chunk") -# voxels_out[z0:z1] = implant_chunk +for z in tqdm.tqdm(range(0,nz,chunk_size),"Loading and thresholding voxels"): + chunk_length = min(chunk_size,nz-z) + load_slice(voxel_chunk, f"{binary_root}/voxels/{scale}x/{sample}.uint16", + (chunk_length,0,0), (nz,ny,nx)) + noisy_implant[z:z+chunk_length] = voxel_chunk[:chunk_length] -# h5in.close() -# h5out.close() + +print(f"Computing connected components") +label, n_features = ndi.label(noisy_implant) +print(f"Counting component volumes") +bincnts = np.bincount(label[label>0],minlength=n_features+1) + +print(f"Writing largest connected component to {output_dir}/{sample}.npz") +largest_cc_ix = np.argmax(bincnts) +implant_mask=(label==largest_cc_ix) +np.savez_compressed(f"{output_dir}/{sample}.npz",implant_mask=implant_mask) +