def process_rgb_histogram(hist, omit=[]): """ omit unwanted bins and normalize histogram by dividing out total # pixels :param hist: color channel histogram with 256 bins :param omit: pixel value bins to omit, default [] :return: normalized histogram (np.array) """ import numpy as np from accessory import get_iterable if len(hist) != 256: msg = 'ERROR [process_rgb_histogram] Input histogram must contain ' \ '256 bins (1 per pixel). Actual bin number = %d. ' % len(hist) print(msg) logging.error(msg) sys.exit() hist = np.array(hist).astype('float') for ii in get_iterable(omit): hist[ii] = 0 tot_pix = sum(hist) try: norm_hist = np.divide(hist, tot_pix) except RuntimeWarning: msg = 'Trying to normalize histogram by dividing by 0 ' \ 'Setting norm_hist to 0 in result.' logging.debug(msg) norm_hist = np.zeros(len(hist)) return norm_hist
def rgbstring2index(rgbstring): """ converts RGB string into array containing corresponding channel indices :param rgbstring: string of letters specifying desired color channels :return: array of rgb channel index (np.array) """ import numpy as np import re from accessory import get_iterable if len(re.findall('[rgb]', rgbstring.lower())) != len(rgbstring): msg = 'ERROR [rgbstring2index] Input string ' + \ rgbstring + 'must contain only r, g, or b characters.' print(msg) logging.error(msg) sys.exit() idx = np.array([]) if 'r' in rgbstring.lower(): idx = np.append(idx, 0) if 'g' in rgbstring.lower(): idx = np.append(idx, 1) if 'b' in rgbstring.lower(): idx = np.append(idx, 2) idx = idx.astype('int') return get_iterable(idx)
def calc_median(img, omit=[]): """ calculate median pixel value of image :param img: 2D array of pixel values :param omit: pixel values to omit from calculation :return: median """ import numpy as np from accessory import get_iterable if np.ndim(img) > 2: msg = 'ERROR [calc_median] Input image must be 2D grayscale (not ' \ 'RGB).' logging.error(msg) print(msg) sys.exit() # collapse image into array pixels = np.ravel(np.array(img)) pixels = pixels.astype('float') # omit specified pixel values from median calculation for omit_idx in get_iterable(omit): pixels[pixels == omit_idx] = np.nan pixels = pixels[np.isfinite(pixels)] median = np.median(pixels) return median
def calc_mode(hist, omit=[]): """ calculate mode from histogram :param hist: histogram values for 0-255 :param omit: pixel values to omit from calculation :return: mode """ import numpy as np from accessory import get_iterable if np.ndim(hist) > 1: msg = 'ERROR [calc_mode] Input must be 1D array of histogram ' \ 'frequency values.' logging.error(msg) print(msg) sys.exit() if np.size(hist) > 256: msg = 'ERROR [calc_mode] Input histogram data has > 256 bins.' logging.error(msg) print(msg) sys.exit() for omit_idx in get_iterable(omit): hist[omit_idx] = 0 # find the index of the histogram maximum mode = np.argmax(hist) return mode
def test_get_iterable(): from accessory import get_iterable import numpy as np vec = [] actual = [ii for ii in get_iterable(vec)] expected = [] assert np.array_equal(actual, expected) vec = 4 actual = [ii for ii in get_iterable(vec)] expected = [vec] assert np.array_equal(actual, expected) vec = (0, 5) actual = [ii for ii in get_iterable(vec)] expected = vec assert np.array_equal(actual, expected)
def otsu_threshold(img, omit=[], verb=False, outfile='./otsu_img.png'): """ calculate the global otsu's threshold for image :param img: 2D array of pixel values :param omit: pixel values to omit from calculation :param verb: verbose mode to display threshold image :param outfile: file to output otsu image if verbose :return: threshold (float) """ from skimage.filters import threshold_otsu import numpy as np from accessory import get_iterable if np.ndim(img) > 2: msg = 'ERROR [otsu_threshold] Input image must be 2D grayscale (not ' \ 'RGB).' logging.error(msg) print(msg) sys.exit() otsu_img = np.array(img) # set omitted pixel values as 0 for omit_idx in get_iterable(omit): otsu_img[img == omit_idx] = np.nan otsu_img[np.isnan(otsu_img)] = 0 threshold_global_otsu = threshold_otsu(otsu_img) if verb: import matplotlib.pyplot as plt from accessory import create_dir global_otsu = otsu_img >= threshold_global_otsu plt.imshow(global_otsu, cmap=plt.cm.gray) msg = '[otsu_threshold] Saving Otsu threshold image: %s' % outfile logging.info(msg) print(msg) create_dir(outfile) plt.savefig(outfile) plt.clf() return threshold_global_otsu