|
import numpy as np |
|
import cv2 |
|
from scipy import ndimage as ndi |
|
from skimage import filters |
|
|
|
|
|
class XDoG: |
|
|
|
def __init__(self, |
|
gamma=0.98, |
|
phi=200, |
|
eps=-0.1, |
|
sigma=0.8, |
|
k=10, |
|
binarize: bool = True): |
|
""" |
|
XDoG algorithm. |
|
|
|
Args: |
|
gamma: Control the size of the Gaussian filter |
|
phi: Control changes in edge strength |
|
eps: Threshold for controlling edge strength |
|
sigma: The standard deviation of the Gaussian filter controls the degree of smoothness |
|
k: Control the size ratio of Gaussian filter, (k=10 or k=1.6) |
|
binarize(bool): Whether to binarize the output |
|
""" |
|
|
|
super(XDoG, self).__init__() |
|
|
|
self.gamma = gamma |
|
assert 0 <= self.gamma <= 1 |
|
|
|
self.phi = phi |
|
assert 0 <= self.phi <= 1500 |
|
|
|
self.eps = eps |
|
assert -1 <= self.eps <= 1 |
|
|
|
self.sigma = sigma |
|
assert 0.1 <= self.sigma <= 10 |
|
|
|
self.k = k |
|
assert 1 <= self.k <= 100 |
|
|
|
self.binarize = binarize |
|
|
|
def __call__(self, img): |
|
|
|
if len(img.shape) == 3 and img.shape[2] == 3: |
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
|
elif len(img.shape) == 3 and img.shape[2] == 4: |
|
img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY) |
|
|
|
if np.isnan(img).any(): |
|
img[np.isnan(img)] = np.mean(img[~np.isnan(img)]) |
|
|
|
|
|
imf1 = ndi.gaussian_filter(img, self.sigma) |
|
imf2 = ndi.gaussian_filter(img, self.sigma * self.k) |
|
imdiff = imf1 - self.gamma * imf2 |
|
|
|
|
|
imdiff = (imdiff < self.eps) * 1.0 + (imdiff >= self.eps) * (1.0 + np.tanh(self.phi * imdiff)) |
|
|
|
|
|
imdiff -= imdiff.min() |
|
imdiff /= imdiff.max() |
|
|
|
if self.binarize: |
|
th = filters.threshold_otsu(imdiff) |
|
imdiff = (imdiff >= th).astype('float32') |
|
|
|
return imdiff |
|
|