def rgb2lchTensor(rgb): rgb /= 255. mask = rgb > 0.04045 rgb[mask] = torch.pow(((rgb[mask] + 0.055) / 1.055), 2.4) rgb[~mask] /= 12.92 # scale by CIE XYZ tristimulus values of the reference white point rgb = (rgb @ xyz_from_rgb) / xyz_ref_white # Nonlinear distortion and linear transformation mask = rgb > 0.008856 rgb[mask] = torch.pow(rgb[mask], 1 / 3) rgb[~mask] = 7.787 * rgb[~mask] + 16. / 116. x, y, z = rgb[..., 0], rgb[..., 1], rgb[..., 2] # Vector scaling L = (116. * y) - 16. a = 500.0 * (x - y) b = 200.0 * (y - z) rgb = torch.cat([x[..., np.newaxis] for x in [L, a, b]], axis=-1) a, b = rgb[..., 1], rgb[..., 2] a, b = torch.hypot(a, b), torch.atan2(b, a) b += torch.where(a < 0., 2 * np.pi, 0.) rgb[..., 1], rgb[..., 2] = a, b rgb[rgb < 0] = 0 return rgb
def pointwise_ops(self): a = torch.randn(4) b = torch.randn(4) t = torch.tensor([-1, -2, 3], dtype=torch.int8) r = torch.tensor([0, 1, 10, 0], dtype=torch.int8) t = torch.tensor([-1, -2, 3], dtype=torch.int8) s = torch.tensor([4, 0, 1, 0], dtype=torch.int8) f = torch.zeros(3) g = torch.tensor([-1, 0, 1]) w = torch.tensor([0.3810, 1.2774, -0.2972, -0.3719, 0.4637]) return ( torch.abs(torch.tensor([-1, -2, 3])), torch.absolute(torch.tensor([-1, -2, 3])), torch.acos(a), torch.arccos(a), torch.acosh(a.uniform_(1.0, 2.0)), torch.add(a, 20), torch.add(a, torch.randn(4, 1), alpha=10), torch.addcdiv(torch.randn(1, 3), torch.randn(3, 1), torch.randn(1, 3), value=0.1), torch.addcmul(torch.randn(1, 3), torch.randn(3, 1), torch.randn(1, 3), value=0.1), torch.angle(a), torch.asin(a), torch.arcsin(a), torch.asinh(a), torch.arcsinh(a), torch.atan(a), torch.arctan(a), torch.atanh(a.uniform_(-1.0, 1.0)), torch.arctanh(a.uniform_(-1.0, 1.0)), torch.atan2(a, a), torch.bitwise_not(t), torch.bitwise_and(t, torch.tensor([1, 0, 3], dtype=torch.int8)), torch.bitwise_or(t, torch.tensor([1, 0, 3], dtype=torch.int8)), torch.bitwise_xor(t, torch.tensor([1, 0, 3], dtype=torch.int8)), torch.ceil(a), torch.clamp(a, min=-0.5, max=0.5), torch.clamp(a, min=0.5), torch.clamp(a, max=0.5), torch.clip(a, min=-0.5, max=0.5), torch.conj(a), torch.copysign(a, 1), torch.copysign(a, b), torch.cos(a), torch.cosh(a), torch.deg2rad( torch.tensor([[180.0, -180.0], [360.0, -360.0], [90.0, -90.0]])), torch.div(a, b), torch.divide(a, b, rounding_mode="trunc"), torch.divide(a, b, rounding_mode="floor"), torch.digamma(torch.tensor([1.0, 0.5])), torch.erf(torch.tensor([0.0, -1.0, 10.0])), torch.erfc(torch.tensor([0.0, -1.0, 10.0])), torch.erfinv(torch.tensor([0.0, 0.5, -1.0])), torch.exp(torch.tensor([0.0, math.log(2.0)])), torch.exp2(torch.tensor([0.0, math.log(2.0), 3.0, 4.0])), torch.expm1(torch.tensor([0.0, math.log(2.0)])), torch.fake_quantize_per_channel_affine( torch.randn(2, 2, 2), (torch.randn(2) + 1) * 0.05, torch.zeros(2), 1, 0, 255, ), torch.fake_quantize_per_tensor_affine(a, 0.1, 0, 0, 255), torch.float_power(torch.randint(10, (4, )), 2), torch.float_power(torch.arange(1, 5), torch.tensor([2, -3, 4, -5])), torch.floor(a), # torch.floor_divide(torch.tensor([4.0, 3.0]), torch.tensor([2.0, 2.0])), # torch.floor_divide(torch.tensor([4.0, 3.0]), 1.4), torch.fmod(torch.tensor([-3, -2, -1, 1, 2, 3]), 2), torch.fmod(torch.tensor([1, 2, 3, 4, 5]), 1.5), torch.frac(torch.tensor([1.0, 2.5, -3.2])), torch.randn(4, dtype=torch.cfloat).imag, torch.ldexp(torch.tensor([1.0]), torch.tensor([1])), torch.ldexp(torch.tensor([1.0]), torch.tensor([1, 2, 3, 4])), torch.lerp(torch.arange(1.0, 5.0), torch.empty(4).fill_(10), 0.5), torch.lerp( torch.arange(1.0, 5.0), torch.empty(4).fill_(10), torch.full_like(torch.arange(1.0, 5.0), 0.5), ), torch.lgamma(torch.arange(0.5, 2, 0.5)), torch.log(torch.arange(5) + 10), torch.log10(torch.rand(5)), torch.log1p(torch.randn(5)), torch.log2(torch.rand(5)), torch.logaddexp(torch.tensor([-1.0]), torch.tensor([-1, -2, -3])), torch.logaddexp(torch.tensor([-100.0, -200.0, -300.0]), torch.tensor([-1, -2, -3])), torch.logaddexp(torch.tensor([1.0, 2000.0, 30000.0]), torch.tensor([-1, -2, -3])), torch.logaddexp2(torch.tensor([-1.0]), torch.tensor([-1, -2, -3])), torch.logaddexp2(torch.tensor([-100.0, -200.0, -300.0]), torch.tensor([-1, -2, -3])), torch.logaddexp2(torch.tensor([1.0, 2000.0, 30000.0]), torch.tensor([-1, -2, -3])), torch.logical_and(r, s), torch.logical_and(r.double(), s.double()), torch.logical_and(r.double(), s), torch.logical_and(r, s, out=torch.empty(4, dtype=torch.bool)), torch.logical_not(torch.tensor([0, 1, -10], dtype=torch.int8)), torch.logical_not( torch.tensor([0.0, 1.5, -10.0], dtype=torch.double)), torch.logical_not( torch.tensor([0.0, 1.0, -10.0], dtype=torch.double), out=torch.empty(3, dtype=torch.int16), ), torch.logical_or(r, s), torch.logical_or(r.double(), s.double()), torch.logical_or(r.double(), s), torch.logical_or(r, s, out=torch.empty(4, dtype=torch.bool)), torch.logical_xor(r, s), torch.logical_xor(r.double(), s.double()), torch.logical_xor(r.double(), s), torch.logical_xor(r, s, out=torch.empty(4, dtype=torch.bool)), torch.logit(torch.rand(5), eps=1e-6), torch.hypot(torch.tensor([4.0]), torch.tensor([3.0, 4.0, 5.0])), torch.i0(torch.arange(5, dtype=torch.float32)), torch.igamma(a, b), torch.igammac(a, b), torch.mul(torch.randn(3), 100), torch.multiply(torch.randn(4, 1), torch.randn(1, 4)), torch.mvlgamma(torch.empty(2, 3).uniform_(1.0, 2.0), 2), torch.tensor([float("nan"), float("inf"), -float("inf"), 3.14]), torch.nan_to_num(w), torch.nan_to_num(w, nan=2.0), torch.nan_to_num(w, nan=2.0, posinf=1.0), torch.neg(torch.randn(5)), # torch.nextafter(torch.tensor([1, 2]), torch.tensor([2, 1])) == torch.tensor([eps + 1, 2 - eps]), torch.polygamma(1, torch.tensor([1.0, 0.5])), torch.polygamma(2, torch.tensor([1.0, 0.5])), torch.polygamma(3, torch.tensor([1.0, 0.5])), torch.polygamma(4, torch.tensor([1.0, 0.5])), torch.pow(a, 2), torch.pow(torch.arange(1.0, 5.0), torch.arange(1.0, 5.0)), torch.rad2deg( torch.tensor([[3.142, -3.142], [6.283, -6.283], [1.570, -1.570]])), torch.randn(4, dtype=torch.cfloat).real, torch.reciprocal(a), torch.remainder(torch.tensor([-3.0, -2.0]), 2), torch.remainder(torch.tensor([1, 2, 3, 4, 5]), 1.5), torch.round(a), torch.rsqrt(a), torch.sigmoid(a), torch.sign(torch.tensor([0.7, -1.2, 0.0, 2.3])), torch.sgn(a), torch.signbit(torch.tensor([0.7, -1.2, 0.0, 2.3])), torch.sin(a), torch.sinc(a), torch.sinh(a), torch.sqrt(a), torch.square(a), torch.sub(torch.tensor((1, 2)), torch.tensor((0, 1)), alpha=2), torch.tan(a), torch.tanh(a), torch.trunc(a), torch.xlogy(f, g), torch.xlogy(f, g), torch.xlogy(f, 4), torch.xlogy(2, g), )
def _sym_ortho(a, b, out): torch.hypot(a, b, out=out[2]) torch.div(a, out[2], out=out[0]) torch.div(b, out[2], out=out[1]) return out
torch.logical_or(r.double(), s) torch.logical_or(r, s, out=torch.empty(4, dtype=torch.bool)) # logical_xor torch.logical_xor(torch.tensor([True, False, True]), torch.tensor([True, False, False])) torch.logical_xor(r, s) torch.logical_xor(r.double(), s.double()) torch.logical_xor(r.double(), s) torch.logical_xor(r, s, out=torch.empty(4, dtype=torch.bool)) # logit torch.logit(torch.rand(5), eps=1e-6) # hypot torch.hypot(torch.tensor([4.0]), torch.tensor([3.0, 4.0, 5.0])) # i0 torch.i0(torch.arange(5, dtype=torch.float32)) # igamma/igammac a1 = torch.tensor([4.0]) a2 = torch.tensor([3.0, 4.0, 5.0]) torch.igamma(a1, a2) torch.igammac(a1, a2) # mul/multiply torch.mul(torch.randn(3), 100) torch.multiply(torch.randn(4, 1), torch.randn(1, 4)) # mvlgamma
def distance_transform(image: torch.Tensor, kernel_size: int = 3, h: float = 0.35) -> torch.Tensor: r"""Approximates the Manhattan distance transform of images using cascaded convolution operations. The value at each pixel in the output represents the distance to the nearest non-zero pixel in the image image. It uses the method described in :cite:`pham2021dtlayer`. The transformation is applied independently across the channel dimension of the images. Args: image: Image with shape :math:`(B,C,H,W)`. kernel_size: size of the convolution kernel. h: value that influence the approximation of the min function. Returns: tensor with shape :math:`(B,C,H,W)`. Example: >>> tensor = torch.zeros(1, 1, 5, 5) >>> tensor[:,:, 1, 2] = 1 >>> dt = kornia.contrib.distance_transform(tensor) """ if not isinstance(image, torch.Tensor): raise TypeError(f"image type is not a torch.Tensor. Got {type(image)}") if not len(image.shape) == 4: raise ValueError( f"Invalid image shape, we expect BxCxHxW. Got: {image.shape}") if kernel_size % 2 == 0: raise ValueError("Kernel size must be an odd number.") # n_iters is set such that the DT will be able to propagate from any corner of the image to its far, # diagonally opposite corner n_iters: int = math.ceil( max(image.shape[2], image.shape[3]) / math.floor(kernel_size / 2)) grid = create_meshgrid(kernel_size, kernel_size, normalized_coordinates=False, device=image.device, dtype=image.dtype) grid -= math.floor(kernel_size / 2) kernel = torch.hypot(grid[0, :, :, 0], grid[0, :, :, 1]) kernel = torch.exp(kernel / -h).unsqueeze(0) out = torch.zeros_like(image) # It is possible to avoid cloning the image if boundary = image, but this would require modifying the image tensor. boundary = image.clone() signal_ones = torch.ones_like(boundary) for i in range(n_iters): cdt = filter2d(boundary, kernel, border_type='replicate') cdt = -h * torch.log(cdt) # We are calculating log(0) above. cdt = torch.nan_to_num(cdt, posinf=0.0) mask = torch.where(cdt > 0, 1.0, 0.0) if mask.sum() == 0: break offset: int = i * kernel_size // 2 out += (offset + cdt) * mask boundary = torch.where(mask == 1, signal_ones, boundary) return out