Skip to content

Instantly share code, notes, and snippets.

@letmaik
Last active January 22, 2021 20:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save letmaik/9880622 to your computer and use it in GitHub Desktop.
Save letmaik/9880622 to your computer and use it in GitHub Desktop.
Adaptive threshold with masking (two versions)
from __future__ import division
import numpy as np
from scipy.ndimage.filters import correlate1d
def masked_adaptive_threshold(image,mask,max_value,size,C):
'''
image must already be masked (unmasked areas=0)
mask is a boolean array
see http://stackoverflow.com/a/10015315/60982
'''
block = np.ones(size, dtype='d')
conv = correlate1d(image.astype(np.uint64), block, axis=0, mode='constant')
conv = correlate1d(conv, block, axis=1, mode='constant')
conv -= image # only consider neighbors
number_neighbours = correlate1d(mask.astype(np.uint64), block, axis=0, mode='constant')
number_neighbours = correlate1d(number_neighbours, block, axis=1, mode='constant')
number_neighbours -= mask # only count neighbors
mean_conv = conv / number_neighbours
binary = np.zeros_like(image)
binary[np.logical_and(image > mean_conv - C, mask)] = max_value
return binary
import cv2
def masked_adaptive_threshold2(image,mask,max_value,size,C):
'''
image must already be masked (unmasked areas=0)
mask is a boolean array
same as masked_adaptive_threshold but very fast, becomes slightly
inaccurate on very dark areas
see http://stackoverflow.com/a/10551103/60982
'''
mask = mask.astype(np.uint8) * 255
conv = cv2.blur(image, (size, size)).astype(float)
number_neighbours = cv2.blur(mask, (size, size)).astype(float)
image = image-255*(conv/number_neighbours)
binary = np.zeros_like(image, dtype=np.uint8)
binary[np.logical_and(image > -C, mask)] = max_value
return binary
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment