Source code for ddd_pylib.morphology._kernels

from abc import ABC, abstractmethod
import numpy as np


[docs] class Kernel: validShapes = ['Circle', 'Square', 'Diamond'] class _Kernel(ABC): def __init__(self, shape, radius): if radius < 1: raise ValueError("Radius must be a positive integer.") self.shape = shape self.radius = radius self.kernel = self.createKernel() def setShape(self, shape): if shape not in self.getValidShapes(): raise ValueError(f"Invalid shape: {shape}. Valid shapes are: {self.getValidShapes()}") self.shape = shape def getValidShapes(self): return Kernel.validShapes @abstractmethod def createKernel(self): raise Exception("Abstract method createKernel of class Kernel called!") class _Kernel2D(_Kernel): def __init__(self, shape, radius): super().__init__(shape, radius) self.kernel = self.createKernel() def makeCircle(self, radius): y, x = np.ogrid[-radius: radius + 1, -radius: radius + 1] mask = x**2 + y**2 <= radius**2 return mask.astype(np.uint8) def makeSquare(self, radius): size = 2 * radius + 1 return np.ones((size, size), dtype=np.uint8) def makeDiamond(self, radius): size = 2 * radius + 1 mask = np.zeros((size, size), dtype=np.uint8) for i in range(size): for j in range(size): if abs(i - radius) + abs(j - radius) <= radius: mask[i, j] = 1 return mask.astype(np.uint8) def createKernel(self): if self.shape == 'Circle': return self.makeCircle(self.radius) elif self.shape == 'Square': return self.makeSquare(self.radius) elif self.shape == 'Diamond': return self.makeDiamond(self.radius) else: raise ValueError(f"Invalid shape: {self.shape}. Valid shapes are: {self.getValidShapes()}") class _Kernel3D(_Kernel): def __init__(self, shape, radius, anisotropy=1.0): super().__init__(shape, radius) self.anisotropy = anisotropy self.kernel = self.createKernel() def makeCircle(self, radius, anisotropy): z_radius = int(radius * anisotropy) y, x, z = np.ogrid[-radius: radius + 1, -radius: radius + 1, -z_radius: z_radius + 1] mask = x**2 + y**2 + (z / anisotropy)**2 <= radius**2 return mask.astype(np.uint8) def createKernel(self): if self.shape == 'Circle': return self.makeCircle(self.radius, self.anisotropy) elif self.shape == 'Square': return self.makeSquare(self.radius) elif self.shape == 'Diamond': return self.makeDiamond(self.radius) else: raise ValueError(f"Invalid shape: {self.shape}. Valid shapes are: {self.getValidShapes()}") def makeSquare(self, radius): size = 2 * radius + 1 return np.ones((size, size, size), dtype=np.uint8) def makeDiamond(self, radius): size = 2 * radius + 1 mask = np.zeros((size, size, size), dtype=np.uint8) for i in range(size): for j in range(size): for k in range(size): if abs(i - radius) + abs(j - radius) + abs(k - radius) <= radius: mask[i, j, k] = 1 return mask.astype(np.uint8)
[docs] @staticmethod def makeKernel(shape, radius, dims, scale={}): if 'Z' in dims: scale_axes = {ax: scale.get(ax, 1.0) for ax in dims} return Kernel._Kernel3D(shape, radius, scale_axes['Z']/scale_axes['X']).kernel else: return Kernel._Kernel2D(shape, radius).kernel
if __name__ == "__main__": shape = 'Circle' radius = 3 dims = ['Y', 'X'] kernel = Kernel.makeKernel(shape, radius, dims)