Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to nichart_mrisnapshot branch #9

Merged
merged 4 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 73 additions & 6 deletions MRISnapshot/create_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ def parse_config(df_conf, list_col_names):
cols_default = ['id_col', 'ulay_col', 'mask_col', 'olay_col', 'olay_col2', 'sel_vals_olay',
'sel_vals_olay2', 'view_plane', 'num_slice', 'step_size_slice',
'min_vox', 'crop_to_mask', 'crop_to_olay', 'padding_ratio', 'bin_olay',
'segment_olay', 'num_classes_olay',
'is_edge', 'alpha_olay', 'perc_high', 'perc_low',
'is_out_single', 'is_out_noqc', 'img_width',
'label_checkbox1', 'label_checkbox2', 'label_editbox']
vals_default = ['', '', '', '', '', '',
'', 'A', '4', '',
'1', '0', '0', '', '1',
'1', '0', '0', '', '1',
'0', '0',
'1', '1', '99', '1',
'1', '0', '300',
'PASS', 'FAIL', 'Notes']
Expand Down Expand Up @@ -104,7 +106,8 @@ def parse_config(df_conf, list_col_names):
params.sel_vals_olay2 = [int(n) for n in params.sel_vals_olay2.split('+') if n != '']

### Convert numeric args from str to int or float
for tmp_arg in ['num_slice', 'step_size_slice', 'min_vox', 'crop_to_mask', 'crop_to_olay', 'bin_olay',
for tmp_arg in ['num_slice', 'step_size_slice', 'min_vox', 'crop_to_mask', 'crop_to_olay', 'bin_olay',
'segment_olay', 'num_classes_olay',
'is_edge', 'is_out_single', 'is_out_noqc', 'img_width']:
if params[tmp_arg] != '':
params[tmp_arg] = int(params[tmp_arg])
Expand All @@ -118,6 +121,20 @@ def parse_config(df_conf, list_col_names):
params.alpha_olay = 1
logger.warning(' Parameter alpha_olay is set to 1, because is_edge was set to 1')

### Correct inconsistent parameters
if (params.segment_olay == 1):
if params.num_classes_olay > 10:
params.num_classes_olay = 10
logger.warning(' Parameter num_classes_olay is set to 10 (max value)')
if params.num_classes_olay < 2:
params.num_classes_olay = 2
logger.warning(' Parameter num_classes_olay is set to 2 (min value)')
if params.is_edge == 0:
params.is_edge = 1
logger.warning(' Parameter is_edge is set to 1, because segment_olay was set to 1')
params.alpha_olay = 1
logger.warning(' Parameter alpha_olay is set to 1, because is_edge was set to 1')

return params

def create_dir(dir_name):
Expand Down Expand Up @@ -199,6 +216,14 @@ def read_and_check_images(df_images, params, sub_index, orient = 'LPS'):
else:
try:
nii = nib.load(fname)
except:
nii = None
qc_ok_flag = 0
qc_msg = 'Could not read ' + col_name + ' image ' + fname
logger.warning(' ' + qc_msg + ', subject discarded!')
return qc_ok_flag, qc_msg, nii_out, fnames_out

try:
orig_ornt = nib.io_orientation(nii.affine)
targ_ornt = axcodes2ornt(orient)
if np.all(orig_ornt == targ_ornt) == False:
Expand All @@ -207,17 +232,22 @@ def read_and_check_images(df_images, params, sub_index, orient = 'LPS'):
if ref_affine == []:
ref_affine = nii.affine
else:
if (ref_affine - nii.affine).sum() != 0:

## We compare the affine matrix for underlay and overlay images
## - we use 3 digit precision
## otherwise it may be too sensitive to numeric differences in headers
if (np.abs(ref_affine - nii.affine).sum()) > 0.001:
qc_ok_flag = 0
qc_msg = 'Inconsistent image vs. overlay'
qc_msg = 'Inconsistent image vs. overlay: affine matrices in headers not consistent'
logger.warning(' ' + qc_msg + ', subject discarded!')
return qc_ok_flag, qc_msg, nii_out, fnames_out
except:
nii = None
qc_ok_flag = 0
qc_msg = 'Could not read ' + col_name + ' image ' + fname
qc_msg = 'Could not reorient ' + col_name + ' image ' + fname
logger.warning(' ' + qc_msg + ', subject discarded!')
return qc_ok_flag, qc_msg, nii_out, fnames_out


nii_out.append(nii)
fnames_out.append(fname)
Expand Down Expand Up @@ -322,6 +352,37 @@ def scale_img_contrast(nii_img, nii_mask, perc_low, perc_high):
']')
return nii_out

def digitize_olay(nii, num_classes, perc_low = 5, perc_high = 95):
'''Simple quick segmentation of overlay image by quantizing intensities.
The purpose is to make sure that edge detection on overlay will be smooth.
Bins for digitization will be estimated from robust intensity ranges
(using percentile values to exclude outliers)

:param nii: Input nifti image
:param num_classes: Number of classes (digits) in output image

:return nii_out: Output nifti image
'''
## Check input img
if nii == None:
return nii

## Get img data
tmp_img = nii.get_fdata()

## Find min and max intensities
pmin, pmax = np.percentile(tmp_img.flatten(), [perc_low, perc_high])

## Digitize image
tmp_img = np.digitize(tmp_img, np.arange(pmin, pmax, (pmax-pmin)/num_classes))

## Create out nifti
nii_out = nib.Nifti1Image(tmp_img, nii.affine, nii.header)

## Return out nifti
logger.info(' Overlay image segmented to ' + str(num_classes) + ' classes')
return nii_out

def extract_snapshot(img_ulay, img_olay, img_olay2, params, curr_view, curr_slice, slice_index,
sub_id, dir_snapshots_full, list_sel_slices):
''' Extracts an image snapshot based on input parameters, and writes it to
Expand All @@ -345,7 +406,8 @@ def extract_snapshot(img_ulay, img_olay, img_olay2, params, curr_view, curr_slic
img2d_ulay = img_ulay[:,:,curr_slice].astype(float)

# Scale underlay image between 0 and 1
img2d_ulay = (img2d_ulay - img2d_ulay.min()) / (img2d_ulay.max() - img2d_ulay.min())
if img2d_ulay.max() - img2d_ulay.min() > 0:
img2d_ulay = (img2d_ulay - img2d_ulay.min()) / (img2d_ulay.max() - img2d_ulay.min())

## Resize underlay slice
#img2d_ulay = zoom(img2d_ulay, (scX,scY), order=1)
Expand Down Expand Up @@ -633,6 +695,11 @@ def create_snapshots(params, df_images, dir_snapshots_full, out_dir):
## Scale ulay image intensities
nii_ulay = scale_img_contrast(nii_ulay, nii_mask, params.perc_low, params.perc_high)

## Digitize olay image intensities
if params.segment_olay == 1:
nii_olay = digitize_olay(nii_olay, params.num_classes_olay)
nii_olay2 = digitize_olay(nii_olay2, params.num_classes_olay)

### Create snapshots for each orientation
for view_index, curr_view in enumerate(params.view_plane):

Expand Down
6 changes: 4 additions & 2 deletions MRISnapshot/prep_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ def prep_dataset(params):
'crop_to_mask' : 0,
'crop_to_olay' : 0,
'padding_ratio' : 0,
'bin_olay' : 0,
'is_edge' : 1,
'bin_olay' : 0,
'segment_olay' : 0,
'num_classes_olay' : 0,
'is_edge' : 1,
'alpha_olay' : 1,
'perc_high' : 100, 'perc_low' : 0,
'is_out_single' : 0, 'is_out_noqc' : 0,
Expand Down
Loading