|
|
@ -7,121 +7,296 @@ import numpy as np
|
|
|
|
import cv2 as cv
|
|
|
|
import cv2 as cv
|
|
|
|
from skimage import filters as skiflt
|
|
|
|
from skimage import filters as skiflt
|
|
|
|
from skimage import restoration as skirest
|
|
|
|
from skimage import restoration as skirest
|
|
|
|
#from scipy import signal as sig
|
|
|
|
from skimage import morphology as skimorph
|
|
|
|
|
|
|
|
# from scipy import signal as sig
|
|
|
|
from PIL import Image, ImageFilter
|
|
|
|
from PIL import Image, ImageFilter
|
|
|
|
|
|
|
|
import bm3d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Parent class for all the filters
|
|
|
|
|
|
|
|
class filter:
|
|
|
|
class filter:
|
|
|
|
''' Parent class for all the filters.
|
|
|
|
''' Parent class for all the filters.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
:param img: Image to be filtered
|
|
|
|
|
|
|
|
'''
|
|
|
|
self.img = img
|
|
|
|
self.img = img
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class convolve(filter):
|
|
|
|
# --------------------- DENOISING FILTERS ---------------------#
|
|
|
|
''' Convolve with custom kernel using opencv.
|
|
|
|
|
|
|
|
If no kernel is given, use default 3x3 kernel for averaging.
|
|
|
|
|
|
|
|
Possibly useful for custom filters.
|
|
|
|
class gaussian(filter):
|
|
|
|
|
|
|
|
'''Gaussian blur filter from scikit-image.
|
|
|
|
|
|
|
|
Easier to use than opencv version.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
|
|
|
|
kernel = np.array(params["kernel"]) if params["kernel"] else np.ones(
|
|
|
|
|
|
|
|
(ksize, ksize), np.float32) / np.sqrt(ksize)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: ksize: " +
|
|
|
|
# Standard deviation for Gaussian kernel
|
|
|
|
# str(ksize) + " kernel: \n" + str(kernel))
|
|
|
|
sigma = float(params["sigma"]) if params["sigma"] else 1
|
|
|
|
self.img = cv.filter2D(self.img, -1, kernel)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: sigma: " + str(sigma))
|
|
|
|
|
|
|
|
self.img = skiflt.gaussian(
|
|
|
|
|
|
|
|
self.img, sigma=sigma, preserve_range=True)
|
|
|
|
|
|
|
|
|
|
|
|
class blur(filter):
|
|
|
|
|
|
|
|
''' Blur filter from OpenCV.
|
|
|
|
class median(filter):
|
|
|
|
Performs averaging of the image.
|
|
|
|
''' Median blur filter from scikit-image.
|
|
|
|
|
|
|
|
Using this over opencv version as that one is limited to 5x5 kernel.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
# TODO remove try-except
|
|
|
|
# Size of the median filter kernel
|
|
|
|
if(params["anchor"]):
|
|
|
|
# Used kernel is disk of size ksize
|
|
|
|
try:
|
|
|
|
|
|
|
|
anchor = tuple(map(int, params["anchor"].split(',')))
|
|
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
|
|
anchor = tuple(params["anchor"])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
anchor = (-1, -1)
|
|
|
|
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: ksize: " +
|
|
|
|
print("with params: ksize: " + str(ksize))
|
|
|
|
# str(ksize) + " anchor: " + str(anchor))
|
|
|
|
self.img = skiflt.median(self.img, footprint=skimorph.disk(ksize))
|
|
|
|
self.img = cv.blur(self.img, ksize=(ksize, ksize), anchor=anchor)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class gaussian(filter):
|
|
|
|
class bilateral(filter):
|
|
|
|
''' Gaussian blur filter from OpenCV.
|
|
|
|
''' Bilateral filter from opencv.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
|
|
|
|
sigmaX = float(params["sigmaX"]) if params["sigmaX"] else 0
|
|
|
|
|
|
|
|
sigmaY = float(params["sigmaY"]) if params["sigmaY"] else 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Diameter of pixel neighborhood used for filtering
|
|
|
|
|
|
|
|
# This determines how fast the filtering is going to be
|
|
|
|
|
|
|
|
diameter = int(params["diameter"]) if params["diameter"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Standard deviation for grayvalue/color distance
|
|
|
|
|
|
|
|
# A larger value results in averaging of pixels with larger radiometric differences
|
|
|
|
|
|
|
|
sigmaColor = int(params["sigmaColor"]) if params["sigmaColor"] else 75
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: ksize: " + str(ksize) +
|
|
|
|
# Standard deviation for range distance in pixels
|
|
|
|
# " sigmaX: " + str(sigmaX) + " sigmaY: " + str(sigmaY))
|
|
|
|
# A larger value results in averaging of pixels with larger spatial differences
|
|
|
|
self.img = cv.GaussianBlur(self.img, (ksize, ksize), sigmaX, sigmaY)
|
|
|
|
sigmaSpace = int(params["sigmaSpace"]) if params["sigmaSpace"] else 75
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: diameter: " + str(diameter) + " sigmaColor: " +
|
|
|
|
|
|
|
|
str(sigmaColor) + " sigmaSpace: " + str(sigmaSpace))
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
|
|
|
|
self.img = cv.bilateralFilter(
|
|
|
|
|
|
|
|
self.img, diameter, sigmaColor, sigmaSpace)
|
|
|
|
|
|
|
|
|
|
|
|
class median(filter):
|
|
|
|
|
|
|
|
''' Median blur filter from scikit-image.
|
|
|
|
class bilateral_scikit(filter):
|
|
|
|
Using this over opencv version as that one is limited to 5x5 kernel.
|
|
|
|
''' Skimage denoise_bilateral filter.
|
|
|
|
|
|
|
|
Averages pixels based on their distance and color similarity.
|
|
|
|
|
|
|
|
Preserves edges while removing unwanted noise.
|
|
|
|
|
|
|
|
Much slower than opencv implementation.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: ksize: " + str(ksize))
|
|
|
|
# Standard deviation for grayvalue/color distance.
|
|
|
|
self.img = skiflt.median(self.img, footprint=np.ones((ksize, ksize)))
|
|
|
|
# A larger value results in averaging of pixels with larger radiometric differences.
|
|
|
|
|
|
|
|
# Range of values: 0 to 1.
|
|
|
|
|
|
|
|
sigmaColor = float(params["sigmaColor"]
|
|
|
|
|
|
|
|
) if params["sigmaColor"] else 0.1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Standard deviation for range distance in pixels.
|
|
|
|
|
|
|
|
# A larger value results in averaging of pixels with larger spatial differences.
|
|
|
|
|
|
|
|
# Range of values: 0 to image size, recommend not more than 20 pixels.
|
|
|
|
|
|
|
|
sigmaSpace = float(params["sigmaSpace"]
|
|
|
|
|
|
|
|
) if params["sigmaSpace"] else 9.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: sigma_color: " + str(sigmaColor) +
|
|
|
|
|
|
|
|
" sigma_spatial: " + str(sigmaSpace))
|
|
|
|
|
|
|
|
self.img = skirest.denoise_bilateral(
|
|
|
|
|
|
|
|
self.img, sigma_color=sigmaColor, sigma_spatial=sigmaSpace)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0) # converting back to uint8
|
|
|
|
|
|
|
|
|
|
|
|
class bilateral(filter):
|
|
|
|
|
|
|
|
''' Bilateral filter from OpenCV.
|
|
|
|
class nlmeans(filter):
|
|
|
|
|
|
|
|
''' Non-local means filter from scikit-image.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
# Set default values
|
|
|
|
|
|
|
|
d = int(params["d"]) if params["d"] else 1
|
|
|
|
|
|
|
|
sigmaColor = int(params["sigmaColor"]) if params["sigmaColor"] else 75
|
|
|
|
|
|
|
|
sigmaSpace = int(params["sigmaSpace"]) if params["sigmaSpace"] else 75
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: d: " + str(d) + " sigmaColor: " +
|
|
|
|
# Size of patches used for denoising
|
|
|
|
# str(sigmaColor) + " sigmaSpace: " + str(sigmaSpace))
|
|
|
|
patch_size = int(params["patch_size"]) if params["patch_size"] else 5
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
|
|
|
|
self.img = cv.bilateralFilter(self.img, d, sigmaColor, sigmaSpace)
|
|
|
|
# Distance in pixels where to search patches
|
|
|
|
|
|
|
|
patch_distance = int(params["patch_distance"]
|
|
|
|
|
|
|
|
) if params["patch_distance"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Estimated standard deviation of the noise
|
|
|
|
|
|
|
|
sigma = np.mean(skirest.estimate_sigma(self.img))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Cut-off distance, higher means more smoothed image
|
|
|
|
|
|
|
|
h = float(params["h"])*sigma if params["h"] else 0.1*sigma
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: patch_size: " + str(patch_size) + " patch_distance: " +
|
|
|
|
|
|
|
|
str(patch_distance) + " h: " + str(round(h, 4)))
|
|
|
|
|
|
|
|
self.img = skirest.denoise_nl_means(
|
|
|
|
|
|
|
|
self.img, patch_size=patch_size, fast_mode=True, patch_distance=patch_distance, h=h)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0) # converting back to uint8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class total_variation(filter):
|
|
|
|
|
|
|
|
''' Scikit image denoise_tv_chambolle filter from scikit-image.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Performs total variation denoising technique based on original Chambolle paper.
|
|
|
|
|
|
|
|
This filter removes fine detail, but preserves details such as edges.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Denoising weight. Larger values result in more denoising.
|
|
|
|
|
|
|
|
weight = float(params["weight"]) if params["weight"] else 0.1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: weight: " + str(weight))
|
|
|
|
|
|
|
|
self.img = skirest.denoise_tv_chambolle(
|
|
|
|
|
|
|
|
self.img, weight=weight)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0) # converting back to uint8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class block_match(filter):
|
|
|
|
|
|
|
|
'''Block matching filter from bm3d.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This filter is very slow and should be used only on small images
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
sigma = float(params["sigma"]) if params["sigma"] else 20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: sigma: " + str(sigma))
|
|
|
|
|
|
|
|
self.img = bm3d.bm3d(self.img, sigma_psd=sigma,
|
|
|
|
|
|
|
|
stage_arg=bm3d.BM3DStages.ALL_STAGES)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class unsharp_mask_scikit(filter):
|
|
|
|
|
|
|
|
''' Unsharp mask filter from scikit.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Apply blurring using gaussian filter, then subtract the blurred image from the original image.
|
|
|
|
|
|
|
|
Radius parameter is the sigma parameter of the gaussian filter.
|
|
|
|
|
|
|
|
Amount parameter regulates the strength of the unsharp mask.
|
|
|
|
|
|
|
|
Better results than using this from opencv.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
# radius of the gaussian filter
|
|
|
|
|
|
|
|
radius = int(params["radius"]) if params["radius"] else 3
|
|
|
|
|
|
|
|
# strength of the unsharp mask
|
|
|
|
|
|
|
|
amount = float(params["amount"]) if params["amount"] else 1.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: radius: " +
|
|
|
|
|
|
|
|
str(radius) + " amount: " + str(amount))
|
|
|
|
|
|
|
|
self.img = skiflt.unsharp_mask(self.img, radius=radius,
|
|
|
|
|
|
|
|
amount=amount, channel_axis=None)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0) # converting back to uintknapsack
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------- EDGE DETECTION FILTERS -------------------#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class farid(filter):
|
|
|
|
|
|
|
|
''' Farid filter from filters.
|
|
|
|
|
|
|
|
Not sure what this might be used for yet.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.img = skiflt.farid(self.img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------ RIDGE EXTRACTION FILTERS ------------------#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class meijering(filter):
|
|
|
|
|
|
|
|
''' Meijering filter from scikit-image filters.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.img = skiflt.meijering(self.img)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class sato(filter):
|
|
|
|
|
|
|
|
''' Meijering filter from scikit-image filters.
|
|
|
|
|
|
|
|
Exctracts black ridges.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.img = skiflt.sato(self.img)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class hessian(filter):
|
|
|
|
|
|
|
|
''' Hessian filter from scikit-image filters.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sigmas = float(params["sigma"]) if params["sigma"] else 1.2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.img = skiflt.hessian(self.img, sigmas=sigmas)
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img * 255.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------- MISCELLANEOUS FILTERS -------------------#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class invert(filter):
|
|
|
|
|
|
|
|
''' Invert the image using bitwise_not from opencv.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
self.img = cv.bitwise_not(self.img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class scale_values(filter):
|
|
|
|
class scale_values(filter):
|
|
|
|
''' Scale values of the image to use the entire range of data type.
|
|
|
|
''' Scale values of the image to use the entire range of data type.
|
|
|
|
This should remove the line height issues.
|
|
|
|
This should remove the line height issues.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
# do this once for inverted image and once for original
|
|
|
|
# scale once for inverted image and once for original
|
|
|
|
# this is done to get whiter whites and blacker blacks
|
|
|
|
# this is done to get the full value range of the data type
|
|
|
|
# which helps to get exact line height on stl model
|
|
|
|
# which might help getting exact line height on stl model
|
|
|
|
tmp = cv.bitwise_not(self.img.astype(np.uint8))
|
|
|
|
tmp = cv.bitwise_not(self.img.astype(np.uint8))
|
|
|
|
coef = 255 / np.max(tmp)
|
|
|
|
coef = 255 / np.max(tmp)
|
|
|
|
tmp = tmp * coef
|
|
|
|
tmp = tmp * coef
|
|
|
@ -139,8 +314,8 @@ class binarize(filter):
|
|
|
|
maxval = int(params["maxval"]) if params["maxval"] else 255
|
|
|
|
maxval = int(params["maxval"]) if params["maxval"] else 255
|
|
|
|
type = int(params["type"]) if params["type"] else 0
|
|
|
|
type = int(params["type"]) if params["type"] else 0
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: threshold: " + str(threshold) +
|
|
|
|
print("with params: threshold: " + str(threshold) +
|
|
|
|
# " maxval: " + str(maxval) + " type: " + str(type))
|
|
|
|
" maxval: " + str(maxval) + " type: " + str(type))
|
|
|
|
self.img = cv.threshold(self.img, threshold, maxval, type)[1]
|
|
|
|
self.img = cv.threshold(self.img, threshold, maxval, type)[1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -151,96 +326,75 @@ class add_margin(filter):
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
margin = int(params["margin"]) if params["margin"] else 10
|
|
|
|
margin = int(params["margin"]) if params["margin"] else 10
|
|
|
|
color = int(params["color"]) if params["color"] else 255
|
|
|
|
color = int(params["color"]) if params["color"] else 255
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: margin: " + str(margin) + " color: " + str(color))
|
|
|
|
|
|
|
|
|
|
|
|
self.fig.set_size_inches(
|
|
|
|
self.fig.set_size_inches(
|
|
|
|
((self.width + 2 * margin) / self.dpi, (self.height + 2 * margin) / self.dpi))
|
|
|
|
((self.width + 2 * margin) / self.dpi, (self.height + 2 * margin) / self.dpi))
|
|
|
|
self.img = cv.copyMakeBorder(
|
|
|
|
self.img = cv.copyMakeBorder(
|
|
|
|
self.img, margin, margin, margin, margin, cv.BORDER_CONSTANT, value=color)
|
|
|
|
self.img, margin, margin, margin, margin, cv.BORDER_CONSTANT, value=color)
|
|
|
|
self.height, self.width = self.img.shape
|
|
|
|
self.height, self.width = self.img.shape
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------- OLD --------------------------#
|
|
|
|
|
|
|
|
|
|
|
|
class denoise(filter):
|
|
|
|
|
|
|
|
# TODO possibly not necessary
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
h = int(params["h"]) if params["h"] else 10
|
|
|
|
|
|
|
|
tWS = int(params["templateWindowSize"]
|
|
|
|
|
|
|
|
) if params["templateWindowSize"] else 7
|
|
|
|
|
|
|
|
sWS = int(params["searchWindowSize"]
|
|
|
|
|
|
|
|
) if params["searchWindowSize"] else 21
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: h: " + str(h) +
|
|
|
|
|
|
|
|
# " tWS: " + str(tWS) + " sWS: " + str(sWS))
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
|
|
|
|
self.img = cv.fastNlMeansDenoising(
|
|
|
|
|
|
|
|
self.img, h, tWS, sWS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: REVISE, REMOVE unused filters
|
|
|
|
|
|
|
|
|
|
|
|
class denoise_bilateral(filter):
|
|
|
|
|
|
|
|
''' Scikit image denoise_bilateral filter.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Performs bilateral denoising technique on the image.
|
|
|
|
class convolve(filter):
|
|
|
|
Averages pixels based on their distance and color similarity.
|
|
|
|
''' Convolve with custom kernel using opencv.
|
|
|
|
Preserves edges while removing unwanted noise.
|
|
|
|
If no kernel is given, use default 3x3 kernel for averaging.
|
|
|
|
|
|
|
|
Possibly useful for custom filters.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
kernel = np.array(params["kernel"]) if params["kernel"] else np.ones(
|
|
|
|
|
|
|
|
(3, 3), np.float32) / 9
|
|
|
|
|
|
|
|
|
|
|
|
# Standard deviation for grayvalue/color distance.
|
|
|
|
print("with params: kernel: \n" + str(kernel))
|
|
|
|
# A larger value results in averaging of pixels with larger radiometric differences.
|
|
|
|
self.img = cv.filter2D(self.img, -1, kernel)
|
|
|
|
sigmaColor = float(params["sigmaColor"]
|
|
|
|
|
|
|
|
) if params["sigmaColor"] else 0.1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Standard deviation for range distance.
|
|
|
|
|
|
|
|
# A larger value results in averaging of pixels with larger spatial differences.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sigmaSpace = float(params["sigmaSpace"]
|
|
|
|
|
|
|
|
) if params["sigmaSpace"] else 15.0
|
|
|
|
|
|
|
|
# Repetition of filter application.
|
|
|
|
|
|
|
|
iterations = int(params["iterations"]) if params["iterations"] else 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: sigma_color: " + str(sigmaColor) +
|
|
|
|
class blur(filter):
|
|
|
|
# " sigma_spatial: " + str(sigmaSpace) + " iterations: " + str(iterations))
|
|
|
|
''' Blur filter from opencv.
|
|
|
|
|
|
|
|
Performs averaging of the image.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(iterations):
|
|
|
|
def __init__(self, img):
|
|
|
|
self.img = skirest.denoise_bilateral(
|
|
|
|
super().__init__(img)
|
|
|
|
self.img, sigma_color=sigmaColor,
|
|
|
|
|
|
|
|
sigma_spatial=sigmaSpace, channel_axis=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
class denoise_tv_chambolle(filter):
|
|
|
|
print("with params: ksize: " + str(ksize))
|
|
|
|
''' Scikit image denoise_tv_chambolle filter from scikit-image.
|
|
|
|
self.img = cv.blur(self.img, ksize=(ksize, ksize))
|
|
|
|
|
|
|
|
|
|
|
|
Performs total variation denoising technique on the image.
|
|
|
|
|
|
|
|
This filter removes fine detail, but preserves edges.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class denoise(filter):
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
h = int(params["h"]) if params["h"] else 10
|
|
|
|
|
|
|
|
tWS = int(params["templateWindowSize"]
|
|
|
|
|
|
|
|
) if params["templateWindowSize"] else 7
|
|
|
|
|
|
|
|
sWS = int(params["searchWindowSize"]
|
|
|
|
|
|
|
|
) if params["searchWindowSize"] else 21
|
|
|
|
|
|
|
|
|
|
|
|
# Denoising weight. The greater weight, the more denoising.
|
|
|
|
# print("with params: h: " + str(h) +
|
|
|
|
weight = float(params["weight"]) if params["weight"] else 0.1
|
|
|
|
# " tWS: " + str(tWS) + " sWS: " + str(sWS))
|
|
|
|
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
# Maximal number of iterations used for the optimization.
|
|
|
|
self.img = cv.fastNlMeansDenoising(
|
|
|
|
iterations = int(params["iterations"]) if params["iterations"] else 1
|
|
|
|
self.img, h, tWS, sWS)
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: weight: " + str(weight) +
|
|
|
|
|
|
|
|
# " iterations: " + str(iterations))
|
|
|
|
|
|
|
|
for i in range(iterations):
|
|
|
|
|
|
|
|
self.img = skirest.denoise_tv_chambolle(
|
|
|
|
|
|
|
|
self.img, weight=weight, channel_axis=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class sharpen(filter):
|
|
|
|
class sharpen(filter):
|
|
|
|
''' Convolution with a sharpening kernel using opencv.
|
|
|
|
''' Convolution with a sharpening kernel using opencv.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
# TODO possibly unnecessary, because unsharp masking is working better
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
@ -248,7 +402,7 @@ class sharpen(filter):
|
|
|
|
kernel = np.matrix(params["kernel"]) if params["kernel"] else np.array(
|
|
|
|
kernel = np.matrix(params["kernel"]) if params["kernel"] else np.array(
|
|
|
|
[[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
|
|
|
|
[[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: kernel: \n" + str(kernel))
|
|
|
|
# print("with params: kernel: \n" + str(kernel))
|
|
|
|
self.img = cv.filter2D(self.img, ddepth=-1, kernel=kernel)
|
|
|
|
self.img = cv.filter2D(self.img, ddepth=-1, kernel=kernel)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -269,43 +423,16 @@ class unsharp_mask(filter):
|
|
|
|
blurred = cv.medianBlur(self.img, ksize)
|
|
|
|
blurred = cv.medianBlur(self.img, ksize)
|
|
|
|
lap = cv.Laplacian(blurred, cv.CV_32F)
|
|
|
|
lap = cv.Laplacian(blurred, cv.CV_32F)
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: strength: " +
|
|
|
|
# print("with params: strength: " +
|
|
|
|
# str(strength) + " ksize: " + str(ksize))
|
|
|
|
# str(strength) + " ksize: " + str(ksize))
|
|
|
|
self.img = blurred - strength*lap
|
|
|
|
self.img = blurred - strength*lap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class unsharp_mask_scikit(filter):
|
|
|
|
|
|
|
|
''' Unsharp mask filter from scikit.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Apply blurring using gaussian filter, then subtract the blurred image from the original image.
|
|
|
|
|
|
|
|
Radius parameter is the sigma parameter of the gaussian filter.
|
|
|
|
|
|
|
|
Amount parameter regulates the strength of the unsharp mask.
|
|
|
|
|
|
|
|
Better results than using opencv module.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
radius = int(params["radius"]) if params["radius"] else 3
|
|
|
|
|
|
|
|
amount = float(params["amount"]) if params["amount"] else 1
|
|
|
|
|
|
|
|
# TODO: i have no idea what this is or how to use it
|
|
|
|
|
|
|
|
channelAxis = int(params["channelAxis"]
|
|
|
|
|
|
|
|
) if params["channelAxis"] else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#self.img = cv.cvtColor(self.img, cv.COLOR_GRAY2RGB)
|
|
|
|
|
|
|
|
#print("with params: radius: " +
|
|
|
|
|
|
|
|
# str(radius) + " amount: " + str(amount))
|
|
|
|
|
|
|
|
self.img = skiflt.unsharp_mask(
|
|
|
|
|
|
|
|
self.img, radius=radius, amount=amount, channel_axis=channelAxis)
|
|
|
|
|
|
|
|
#self.img = cv.cvtColor(self.img, cv.COLOR_RGB2GRAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class unsharp_mask_pil(filter):
|
|
|
|
class unsharp_mask_pil(filter):
|
|
|
|
''' Unsharp mask filter from PIL.
|
|
|
|
''' Unsharp mask filter from PIL.
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
# TODO: does not work
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
@ -320,7 +447,7 @@ class unsharp_mask_pil(filter):
|
|
|
|
# Threshold controls the minimum brightness change that will be sharpened
|
|
|
|
# Threshold controls the minimum brightness change that will be sharpened
|
|
|
|
threshold = int(params["threshold"]) if params["threshold"] else 3
|
|
|
|
threshold = int(params["threshold"]) if params["threshold"] else 3
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: radius: " +
|
|
|
|
# print("with params: radius: " +
|
|
|
|
# str(radius) + " percent: " + str(percent) + " threshold: " + str(threshold))
|
|
|
|
# str(radius) + " percent: " + str(percent) + " threshold: " + str(threshold))
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
self.img = np.uint8(self.img)
|
|
|
|
tmp = Image.fromarray(self.img)
|
|
|
|
tmp = Image.fromarray(self.img)
|
|
|
@ -328,7 +455,27 @@ class unsharp_mask_pil(filter):
|
|
|
|
self.img = np.asarray(tmp)
|
|
|
|
self.img = np.asarray(tmp)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class morph(filter):
|
|
|
|
class erode(filter):
|
|
|
|
|
|
|
|
''' General morphological operations from OpenCV.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Can be used with MORPH_OPEN, MORPH_CLOSE, MORPH_DILATE, MORPH_ERODE and more as 'op'.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, img):
|
|
|
|
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# get an ellipse kernel
|
|
|
|
|
|
|
|
kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement(
|
|
|
|
|
|
|
|
cv.MORPH_ELLIPSE, (3, 3))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("with params: kernel: \n" + str(kernel))
|
|
|
|
|
|
|
|
self.img = cv.morphologyEx(
|
|
|
|
|
|
|
|
np.uint8(self.img), op=cv.MORPH_ERODE, kernel=kernel)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class dilate(filter):
|
|
|
|
''' General morphological operations from OpenCV.
|
|
|
|
''' General morphological operations from OpenCV.
|
|
|
|
|
|
|
|
|
|
|
|
Can be used with MORPH_OPEN, MORPH_CLOSE, MORPH_DILATE, MORPH_ERODE and more as 'op'.
|
|
|
|
Can be used with MORPH_OPEN, MORPH_CLOSE, MORPH_DILATE, MORPH_ERODE and more as 'op'.
|
|
|
@ -338,25 +485,14 @@ class morph(filter):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
# TODO: this is probably better with binarized image
|
|
|
|
|
|
|
|
kernel = np.matrix(params["kernel"]) if params["kernel"] else np.ones(
|
|
|
|
# get an ellipse kernel
|
|
|
|
(3, 3), np.uint8)
|
|
|
|
kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement(
|
|
|
|
iterations = int(params["iterations"]) if params["iterations"] else 1
|
|
|
|
cv.MORPH_ELLIPSE, (3, 3))
|
|
|
|
op = getattr(cv, params["op"]) if params["op"] else cv.MORPH_OPEN
|
|
|
|
|
|
|
|
if(params["anchor"]):
|
|
|
|
print("with params: kernel: \n" + str(kernel))
|
|
|
|
# TODO remove try-except
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
anchor = tuple(map(int, params["anchor"].split(',')))
|
|
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
|
|
anchor = tuple(params["anchor"])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
anchor = (-1, -1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#print("with params: kernel: \n" + str(kernel) + " anchor: " +
|
|
|
|
|
|
|
|
# str(anchor) + " iterations: " + str(iterations) + " op: " + str(op))
|
|
|
|
|
|
|
|
self.img = cv.morphologyEx(
|
|
|
|
self.img = cv.morphologyEx(
|
|
|
|
np.uint8(self.img), op=op, kernel=kernel,
|
|
|
|
np.uint8(self.img), op=cv.MORPH_DILATE, kernel=kernel)
|
|
|
|
anchor=anchor, iterations=iterations)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class gabor(filter):
|
|
|
|
class gabor(filter):
|
|
|
@ -368,11 +504,11 @@ class gabor(filter):
|
|
|
|
def __init__(self, img):
|
|
|
|
def __init__(self, img):
|
|
|
|
super().__init__(img)
|
|
|
|
super().__init__(img)
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: not working properly
|
|
|
|
|
|
|
|
def apply(self, params):
|
|
|
|
def apply(self, params):
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 31
|
|
|
|
ksize = int(params["ksize"]) if params["ksize"] else 31
|
|
|
|
sigma = float(params["sigma"]) if params["sigma"] else 10.0
|
|
|
|
sigma = float(params["sigma"]) if params["sigma"] else 10.0
|
|
|
|
theta = params["theta"] if params["theta"] else [0,np.pi/16,np.pi-np.pi/16]
|
|
|
|
theta = params["theta"] if params["theta"] else [
|
|
|
|
|
|
|
|
0, np.pi/16, np.pi-np.pi/16]
|
|
|
|
lambd = float(params["lambd"]) if params["lambd"] else 10.0
|
|
|
|
lambd = float(params["lambd"]) if params["lambd"] else 10.0
|
|
|
|
gamma = float(params["gamma"]) if params["gamma"] else 0.02
|
|
|
|
gamma = float(params["gamma"]) if params["gamma"] else 0.02
|
|
|
|
psi = float(params["psi"]) if params["psi"] else 0.0
|
|
|
|
psi = float(params["psi"]) if params["psi"] else 0.0
|
|
|
@ -380,7 +516,8 @@ class gabor(filter):
|
|
|
|
filters = []
|
|
|
|
filters = []
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(len(theta)):
|
|
|
|
for i in range(len(theta)):
|
|
|
|
g_kernel = cv.getGaborKernel(ksize=(ksize, ksize), sigma=sigma, theta=theta[i], lambd=lambd, gamma=gamma, psi=psi)
|
|
|
|
g_kernel = cv.getGaborKernel(ksize=(
|
|
|
|
|
|
|
|
ksize, ksize), sigma=sigma, theta=theta[i], lambd=lambd, gamma=gamma, psi=psi)
|
|
|
|
g_kernel = g_kernel / 1.5 * g_kernel.sum()
|
|
|
|
g_kernel = g_kernel / 1.5 * g_kernel.sum()
|
|
|
|
filters.append(g_kernel)
|
|
|
|
filters.append(g_kernel)
|
|
|
|
|
|
|
|
|
|
|
|