Spaces:
Running
Running
# -*- coding: utf-8 -*- | |
# Copyright (c) XiMing Xing. All rights reserved. | |
# Author: XiMing Xing | |
# Description: | |
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): | |
# to gray if image is not already grayscale | |
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)]) | |
# gaussian filter | |
imf1 = ndi.gaussian_filter(img, self.sigma) | |
imf2 = ndi.gaussian_filter(img, self.sigma * self.k) | |
imdiff = imf1 - self.gamma * imf2 | |
# XDoG | |
imdiff = (imdiff < self.eps) * 1.0 + (imdiff >= self.eps) * (1.0 + np.tanh(self.phi * imdiff)) | |
# normalize | |
imdiff -= imdiff.min() | |
imdiff /= imdiff.max() | |
if self.binarize: | |
th = filters.threshold_otsu(imdiff) | |
imdiff = (imdiff >= th).astype('float32') | |
return imdiff | |