Skip to content

Commit

Permalink
Merge branch 'invesalius:master' into context-menu-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
henrikkauppi authored Jun 26, 2024
2 parents 2243d30 + 6608ed7 commit f58a1e6
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 13 deletions.
35 changes: 23 additions & 12 deletions invesalius/data/imagedata_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import gdcm
import imageio
import numpy
import numpy as np

from scipy.ndimage import shift, zoom
Expand All @@ -38,6 +37,7 @@
import invesalius.data.converters as converters
import invesalius.data.coordinates as dco
import invesalius.data.slice_ as sl
import invesalius.gui.dialogs as dlg
import invesalius.reader.bitmap_reader as bitmap_reader
from invesalius.i18n import tr as _
from invesalius.data import vtk_utils as vtk_utils
Expand Down Expand Up @@ -158,7 +158,7 @@ def FixGantryTilt(matrix, spacing, tilt):
Fix gantry tilt given a vtkImageData and the tilt value. Return new
vtkImageData.
"""
angle = numpy.radians(tilt)
angle = np.radians(tilt)
spacing = spacing[0], spacing[1], spacing[2]
gntan = math.tan(angle)

Expand Down Expand Up @@ -308,7 +308,7 @@ def array2memmap(arr, filename=None):
fd = None
if filename is None:
fd, filename = tempfile.mkstemp(prefix="inv3_", suffix=".dat")
matrix = numpy.memmap(filename, mode="w+", dtype=arr.dtype, shape=arr.shape)
matrix = np.memmap(filename, mode="w+", dtype=arr.dtype, shape=arr.shape)
matrix[:] = arr[:]
matrix.flush()
if fd:
Expand Down Expand Up @@ -359,7 +359,7 @@ def bitmap2memmap(files, slice_size, orientation, spacing, resolution_percentage
)

if resolution_percentage == 1.0:
matrix = numpy.memmap(temp_file, mode="w+", dtype="int16", shape=shape)
matrix = np.memmap(temp_file, mode="w+", dtype="int16", shape=shape)

cont = 0
max_scalar = None
Expand Down Expand Up @@ -394,7 +394,7 @@ def bitmap2memmap(files, slice_size, orientation, spacing, resolution_percentage

if not (first_resample_entry):
shape = shape[0], yx_shape[0], yx_shape[1]
matrix = numpy.memmap(temp_file, mode="w+", dtype="int16", shape=shape)
matrix = np.memmap(temp_file, mode="w+", dtype="int16", shape=shape)
first_resample_entry = True

image = image_resized
Expand Down Expand Up @@ -460,7 +460,7 @@ def dcm2memmap(files, slice_size, orientation, resolution_percentage):
else:
shape = len(files), slice_size[1], slice_size[0]

matrix = numpy.memmap(temp_file, mode="w+", dtype="int16", shape=shape)
matrix = np.memmap(temp_file, mode="w+", dtype="int16", shape=shape)
for n, f in enumerate(files):
im_array = read_dcm_slice_as_np2(f, resolution_percentage)[::-1]

Expand Down Expand Up @@ -495,7 +495,7 @@ def dcmmf2memmap(dcm_file, orientation):
if samples_per_pixel == 3:
np_image = image_normalize(rgb2gray(np_image), 0, 255)
temp_fd, temp_file = tempfile.mkstemp()
matrix = numpy.memmap(temp_file, mode="w+", dtype="int16", shape=np_image.shape)
matrix = np.memmap(temp_file, mode="w+", dtype="int16", shape=np_image.shape)
z, y, x = np_image.shape
if orientation == "CORONAL":
spacing = xs, zs, ys
Expand Down Expand Up @@ -532,18 +532,29 @@ def img2memmap(group):
# to be rescalaed so that no negative values are created when converting to int16
# maximum of 10000 was selected arbitrarily by testing with one MRI example
# alternatively could test if "data.dtype == 'float64'" but maybe it is too specific
if numpy.ptp(data) > (2**16/2-1):
if np.ptp(data) > (2**16/2-1):
data = image_normalize(data, min_=0, max_=10000, output_dtype=np.int16)
dlg.WarningRescalePixelValues()

# images can have pixel intensities in small float numbers which after int conversion will
# have to be binary (0, 1). To prevent that, rescale pixel values from 0-255
elif data.max() < (2**3):
data_temp = image_normalize(data, min_=0, max_=255, output_dtype=np.int16)
status = dlg.DialogRescalePixelIntensity(data.max(), np.unique(data_temp).size)

if status:
data = data_temp
# dlg.WarningRescalePixelValues()

# Convert RAS+ to default InVesalius orientation ZYX
data = numpy.swapaxes(data, 0, 2)
data = numpy.fliplr(data)
data = np.swapaxes(data, 0, 2)
data = np.fliplr(data)

matrix = numpy.memmap(temp_file, mode="w+", dtype=np.int16, shape=data.shape)
matrix = np.memmap(temp_file, mode="w+", dtype=np.int16, shape=data.shape)
matrix[:] = data[:]
matrix.flush()

scalar_range = numpy.amin(matrix), numpy.amax(matrix)
scalar_range = np.amin(matrix), np.amax(matrix)
os.close(temp_fd)

return matrix, scalar_range, temp_file
Expand Down
82 changes: 81 additions & 1 deletion invesalius/gui/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,20 @@ def ImportInvalidFiles(ftype="DICOM"):
dlg.Destroy()


def ImportAnalyzeWarning():
def WarningRescalePixelValues():
msg1 = _("Warning! Pixel values are smaller than 8 (possible float values).\n")
msg2 = _("Pixel values have been rescaled from 0-255 for compatibility.")
if sys.platform == 'darwin':
dlg = wx.MessageDialog(None, "", msg1 + msg2,
wx.ICON_INFORMATION | wx.OK)
else:
dlg = wx.MessageDialog(None, msg1 + msg2, "InVesalius 3",
wx.ICON_INFORMATION | wx.OK)
dlg.ShowModal()
dlg.Destroy()


def ImagePixelRescaling():
msg1 = _("Warning! InVesalius has limited support to Analyze format.\n")
msg2 = _("Slices may be wrongly oriented and functions may not work properly.")
if sys.platform == 'darwin':
Expand Down Expand Up @@ -5612,6 +5625,73 @@ def Close(self):
wx.Dialog.Close(self)
self.Destroy()


class SelectNiftiVolumeDialog(wx.Dialog):
def __init__(self, volumes, title=_(u"Select NIfTI volume")):
wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title,
style=wx.DEFAULT_DIALOG_STYLE | wx.FRAME_FLOAT_ON_PARENT)

self._init_gui(volumes)

def _init_gui(self, volumes):

self.cmb_volume = wx.ComboBox(self, -1, choices=volumes, style=wx.CB_DROPDOWN | wx.CB_READONLY)

button_ok = wx.Button(self, wx.ID_OK)
button_ok.SetHelpText("")
button_ok.SetDefault()

button_cancel = wx.Button(self, wx.ID_CANCEL)
button_cancel.SetHelpText("")

button_sizer = wx.StdDialogButtonSizer()
button_sizer.AddButton(button_ok)
button_sizer.AddButton(button_cancel)
button_sizer.Realize()

main_sizer = wx.BoxSizer(wx.VERTICAL)

# main_sizer.Add((5, 5))
# main_sizer.Add(
# wx.StaticText(self, -1, _("Select NIfTI volume:")), 0, wx.EXPAND, 5)
main_sizer.Add((5, 5))
main_sizer.Add(self.cmb_volume, 1, wx.EXPAND | wx.ALL, 5)
main_sizer.Add((5, 5))
main_sizer.Add(button_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
main_sizer.Add((5, 5))

self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.Layout()
self.CenterOnParent()

def GetVolumeChoice(self):
volume_choice = int(self.cmb_volume.GetString(self.cmb_volume.GetSelection())) - 1

return volume_choice


def DialogRescalePixelIntensity(max_intensity, unique_values):
msg = _("Maximum pixel intensity is: ") + str(round(max_intensity, 1)) + '\n\n' + \
_("Number of unique pixel intensities: ") + str(unique_values) + '\n\n' + \
_("Would you like to rescale pixel values to 0-255?")

if sys.platform == 'darwin':
dlg = wx.MessageDialog(None, "", msg,
wx.YES_NO)
else:
dlg = wx.MessageDialog(None, msg, "InVesalius 3",
wx.YES_NO)

if dlg.ShowModal() == wx.ID_YES:
status = True
else:
status = False

dlg.Destroy()
return status


class ConfigureOptitrackDialog(wx.Dialog):
def __init__(self, title=_("Configure Optitrack")):
wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title, size=wx.Size(1000, 200),
Expand Down
31 changes: 31 additions & 0 deletions invesalius/reader/others_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,37 @@ def ReadOthers(dir_):
imagedata = nib.squeeze_image(nib.load(dir_))
imagedata = nib.as_closest_canonical(imagedata)
imagedata.update_header()

if len(imagedata.shape) == 4:
import invesalius.gui.dialogs as dlg
from wx import ID_OK

dialog = dlg.SelectNiftiVolumeDialog(volumes=[str(n+1) for n in range(imagedata.shape[-1])])
status = dialog.ShowModal()

success = status == ID_OK

if success:
# selected_option = int(dialog.choice.GetStringSelection())
selected_volume = dialog.GetVolumeChoice()

data = imagedata.get_fdata()
header = imagedata.header.copy()

selected_volume = data[..., selected_volume]
header.set_data_shape(selected_volume.shape)

zooms = list(header.get_zooms())
new_zooms = zooms[:3] # Adjust this to your desired zooms
header.set_zooms(new_zooms)

imagedata = nib.Nifti1Image(selected_volume, imagedata.affine, header=header)

else:
raise ValueError

dialog.Destroy()

except(nib.filebasedimages.ImageFileError):
return False

Expand Down

0 comments on commit f58a1e6

Please sign in to comment.