def assert_sitk_img_equivalence(img: SimpleITK.Image, img_ref: SimpleITK.Image): assert img.GetDimension() == img_ref.GetDimension() assert img.GetSize() == img_ref.GetSize() assert img.GetOrigin() == img_ref.GetOrigin() assert img.GetSpacing() == img_ref.GetSpacing() assert (img.GetNumberOfComponentsPerPixel() == img_ref.GetNumberOfComponentsPerPixel()) assert img.GetPixelIDValue() == img_ref.GetPixelIDValue() assert img.GetPixelIDTypeAsString() == img_ref.GetPixelIDTypeAsString()
def fitting_index(image: sitk.Image, norm: Union[int, str] = 2.0, centre: Tuple[float, float, float] = None, radius: float = None, padding: bool = True) -> float: r""" Compute the fitting index of an input object. The fitting index of order `p` is defined as the Jaccard coefficient computed between the input object and a p-ball centred in the object's centre of mass. Parameters ---------- image : sitk.Image Input binary image of the object. norm : Union[int,str] Order of the Minkowski norm ('inf' or 'max' to use the Chebyshev norm). centre : Tuple[float, float, float] Forces the p-ball to be centred in a specific point. radius : float Force the radius of the p-ball. padding : bool If `True`, add enough padding to be sure that the ball will entirely fit within the volume. Returns ------- float Value of the fitting index. """ if image.GetPixelID() != sitk.sitkUInt8: raise Exception('Unsupported %s pixel type' % image.GetPixelIDTypeAsString()) if centre is None: # Use the centroid as centre lssif = sitk.LabelShapeStatisticsImageFilter() lssif.Execute(image) centre = lssif.GetCentroid(1) if padding: # Add some padding to be sure that an isovolumetric 1-ball can fit # within the same volume of a sphere touching the boundary pad = tuple([x // 4 for x in image.GetSize()]) image = sitk.ConstantPad(image, pad, pad, 0) image.SetOrigin((0, 0, 0)) centre = tuple([x + y for x, y in zip(centre, pad)]) if radius is None: radius = isovolumteric_radius(image, norm) size = image.GetSize() sphere = drawing.create_sphere(radius, size=size, centre=centre, norm=norm) > 0 return jaccard(image, sphere)
def check_if_image_is_rgb(image: sitk.Image): """Check if an image is RGB by looking for a 3-component 8 bit pixel image""" components = image.GetNumberOfComponentsPerPixel() pixel_type = image.GetPixelIDTypeAsString() if components == 3 and pixel_type == 'vector of 8-bit unsigned integer': image_is_rgb = True else: image_is_rgb = False return image_is_rgb
def minkowski_compactness(image: sitk.Image, norm: Union[int, str] = 1.0) -> float: r""" Compute the Minkovski compactness of a binary image. Minkowski compactness of an object is defined as the ratio between the volume of the object and the volume of a p-ball centred on the object's centre of mass, maximised agaist spatial rotations of the ball. Parameters ---------- image : sitk.Image Input binary image. norm : Union[int,str] Order of the Minkowski norm ('inf' or 'max' to use the Chebyshev norm). Returns ------- float Value of the Minkowski norm. """ if image.GetPixelID() != sitk.sitkUInt8: raise Exception('Unsupported %s pixel type' % image.GetPixelIDTypeAsString()) if norm == 'inf' or norm == 'max': descriptor = 'cubeness' elif norm == 1.0: descriptor = 'octahedroness' else: raise Exception('Unsupported value %s for the norm parameter' % str(norm)) lssif = sitk.LabelShapeStatisticsImageFilter() lssif.Execute(image) a = sitk.GetArrayViewFromImage(image) > 0 return _disptools.shape_descriptor(a, lssif.GetCentroid(1), image.GetSpacing(), descriptor)
def sphericity(image: sitk.Image) -> float: r""" Measure the sphericity of a object. The sphericity is defined [5]_ [6]_ as the ratio between the surface of a sphere with the same volume of the object and the surface of the object itself. .. math:: \frac{\pi^{\frac{1}{3}}(6V)^{\frac{2}{3}}}{A} A sphere has sphericity equal to 1, non-spherical objects have sphericity strictly lesser than 1. References ---------- .. [5] Wadell, Hakon. "Volume, shape, and roundness of quartz particles." The Journal of Geology 43.3 (1935): 250-280. .. [6] Lehmann, Gaëthan. "Label object representation and manipulation with ITK" Insight Journal, July-December 2007 Parameters ---------- image : sitk.Image Input binary (sitkUInt8) image. Returns ------- float A floating point value of sphericity in the interval [0, 1]. """ if image.GetPixelID() != sitk.sitkUInt8: raise Exception('Unsupported %s pixel type' % image.GetPixelIDTypeAsString()) lssif = sitk.LabelShapeStatisticsImageFilter() lssif.Execute(image) return lssif.GetRoundness(1)
def cubicity(image: sitk.Image) -> float: r""" Measure the cubicity of an object. The cubicity is defined [4]_ as the ratio between the volume of the object and the volume of its bounding cube. A cube has cubicity equal to 1, a sphere has cubicity pi/6, and in general non-cubic objects have cubicity strictly lesser than 1. Here the bounding cube is estimated as the cube whose side is equal to the longest side of the oriented bounding box of the object. References ---------- .. [4] O'Flannery, LJ and O'Mahony, MM, "Precise shape grading of coarse aggregate". Magazine of Concrete Research 51.5 (1999), pp. 319-324. Parameters ---------- image : sitk.Image Input binary (sitkUInt8) image. Returns ------- float A floating point value of cubicity in the interval [0, 1]. """ if image.GetPixelID() != sitk.sitkUInt8: raise Exception('Unsupported %s pixel type' % image.GetPixelIDTypeAsString()) # NOTE: the size of the bounding box is already in image space # units, while the volume (number of voxels) needs to be multiplied # by the voxel size dv = functools.reduce(lambda x, y: x * y, image.GetSpacing(), 1.0) try: lssif = sitk.LabelShapeStatisticsImageFilter() lssif.ComputeOrientedBoundingBoxOn() lssif.Execute(image) (s1, s2, s3) = lssif.GetOrientedBoundingBoxSize(1) volume = lssif.GetNumberOfPixels(1) * dv except AttributeError: # Use ITK as a fallback if the method is not available in # SimpleITK if 'itk' not in sys.modules: raise Exception( 'sitk_to_itk: itk module is required to use this feature.') itk_image = drawing.sitk_to_itk(image) li2slmf = itk.LabelImageToShapeLabelMapFilter.IUC3LM3.New(itk_image) li2slmf.ComputeOrientedBoundingBoxOn() statistics = li2slmf()[0][1] # FIXME GetOrientedBoundingBoxSize() seems to be broken # (s1, s2, s3) = statistics.GetOrientedBoundingBoxSize() # (s1, s2, s3) = statistics.GetBoundingBox().GetSize() # FIXME GetBoundingBox is in voxels, GetOrientedBoundingBox is # in image size instead, so multiply by the spacing when using # GetBoundingBox (s1, s2, s3) = [x * s for x, s in zip([s1, s2, s3], image.GetSpacing())] volume = statistics.GetNumberOfPixels() * dv return volume / (max(s1, s2, s3)**3)