Hi all,
We are working on adapting our algorithms to be python plugins running in ImFusion. Something we noticed is that when we run the algorithm once (click on compute), then when we change the parameters of the algorithm (e.g. tx, ty, tz
) via the UI, this change is not taken into account. It might be that we are doing something wrong when defining the parameters. The code for the plugin is provided below:
class DRRGenerationAlgorithm(imfusion.Algorithm):
def __init__(self, image: imfusion.SharedImageSet, mask = None):
super().__init__()
self.image = image
self.mask = mask
self.imageset_out = imfusion.SharedImageSet()
if self.mask == None:
self.add_param('vessel_mask_path', Path(""), attributes="label: 'Vessel Segmentation Mask', tooltip: 'Path to label for vessel compensation'")
self.add_param('algorithm_choice',value=0, attributes="label:'Algorithm', min: 0, max: 2, tooltip: 'Available Algorithms: \n 0: DRR generation \n 1: DRR generation with reference (requires vessel segmentation mask) \n 2: DRR generation with masks (requires vessel segmentation mask)'")
self.add_param('preprocess',value=0, attributes="label:'Preprocess Image', min: 0, max: 1, tooltip: 'Remove the Table from the Image \n 0: No \n 1: Yes'")
self.add_param('xray_device',value=0, attributes="label:'X-Ray Device', min: 0, max: 2, tooltip: '0: Loopx_C \n 1: Loopx \n 2: C-Arm'")
self.add_param('alpha',value=0, attributes="label:'Rotation X', min: 0, max:360")
self.add_param('beta',value=0, attributes="label:'Rotation Y', min: 0, max:360")
self.add_param('gamma',value=0, attributes="label:'Rotation Z', min: 0, max:360")
self.add_param('tx',value=0, attributes="label:'Translation X'")
self.add_param('ty',value=0, attributes="label:'Translation Y'")
self.add_param('tz',value=0, attributes="label:'Translation Z'")
self.sitk_path = None
@classmethod
def convert_input(cls, data):
if len(data) == 1 and isinstance(data[0], imfusion.SharedImageSet):
"""Single Image Case"""
return data, None
if len(data) == 2:
"""Correction Label Mask Case"""
image, mask = data
# Set default to 1 to make sure
if not isinstance(image, imfusion.SharedImageSet):
raise imfusion.IncompatibleError('First input must be a volume')
if not isinstance(mask, imfusion.SharedImageSet) or mask.modality != imfusion.Data.Modality.LABEL:
raise imfusion.IncompatibleError('Second input must be a label map')
return [image], [mask]
raise imfusion.IncompatibleError('Requires exactly one image or two images with a label map')
def preprocess_table(self):
image_imfusion = self.image[0][0]
image_np, spacing = self.parse_image(image_imfusion)
sitk_image = numpy_to_sitk(image_np, spacing)
self.sitk_path = run_remove_table_with_preloaded_image(sitk_image)
return imfusion.Algorithm.Status.SUCCESS
def parse_image(self,image, ret_nifti=False):
affine = image.world_to_image_matrix
spacing = image.spacing
image_np = image.numpy()
new_affine = affine.copy()
for i in range(3): # Assuming 3D image
new_affine[i, i] = spacing[i] # Update the diagonal to new spacing
nifti_image = nib.Nifti1Image(image_np, affine=new_affine)
if ret_nifti:
return nifti_image
else:
return image_np, spacing
def parse_dof(self):
self.dof = [
float(self.alpha),
float(self.beta),
float(self.gamma),
float(self.tx),
float(self.ty),
float(self.tz)
]
def compute(self):
self.parse_dof()
if self.preprocess != 0:
self.preprocess_table()
elif hasattr(self, 'vessel_mask_path') and self.vessel_mask_path != Path("") and os.path.exists(self.vessel_mask_path):
# There is probably an alternative...
self.mask = imfusion.load(str(self.vessel_mask_path))
if self.mask:
mask_imfusion = self.mask[0][0]
image_np, spacing = self.parse_image(mask_imfusion)
sitk_image = numpy_to_sitk(image_np, spacing)
self.vessel_mask_path = "/tmp/label_mask.nii"
sitk.WriteImage(sitk_image, self.vessel_mask_path)
if self.sitk_path == None:
"""Case: No processing of image"""
image_imfusion = self.image[0][0]
image_np, spacing = self.parse_image(image_imfusion)
sitk_image = numpy_to_sitk(image_np, spacing)
self.sitk_path = "/tmp/vol_drr_generation.nii"
sitk.WriteImage(sitk_image, self.sitk_path)
if self.algorithm_choice > 0 and self.vessel_mask_path == Path(""):
logging.warning("No Vessel Segmentation Mask. Running Algorithm 0")
self.algorithm_choice = 0
imgs_numpy = diffdeepdrr(self.sitk_path, self.vessel_mask_path, self.dof, algorithm_choice=self.algorithm_choice, xray_device=self.xray_device, device=device)
for img_numpy in imgs_numpy:
if len(img_numpy.shape) == 2: img_numpy = np.expand_dims(img_numpy, axis=-1)
img_imfusion = imfusion.SharedImage(img_numpy)
self.imageset_out.add(img_imfusion)
def output(self):
return [self.imageset_out]
Also, one further question, how can we change the text shown on the compute button in a python plugin?