def threshold_otsu_median(datafield, pts=256): """ Compute Otsu's threshold with median classifier (histogram mode). Parameters ---------- datafield: gwy.DataField Datafield over which threshold will be computed. pts: int Number of points in histogram. Default 256. Returns ------- threshold: float """ # number of pts for histogram cdf = gwy.DataLine(pts, 0, True) # compute z-scale CDF from image datafield.cdh(cdf, pts) # sort all intensity values vals = sorted(datafield.get_data()) # sort out hist data dx = cdf.get_real() / cdf.get_res() # pixel spacing in data line offset = cdf.get_offset() # dataline offset, ie. 0 index point value in x x = [(i * dx) + offset for i in range(pts)] # construct bin locations # get cdf data as list weight1 = [int(round(i * len(vals))) for i in cdf.get_data()] weight2 = [len(vals) - i for i in weight1[::-1]][::-1] # class medians for all possible thresholds median1 = [vals[:weight1[i]][weight1[i] // 2] for i in range(pts - 1)] median2 = [ vals[::-1][:weight2[i]][weight2[i] // 2] for i in range(pts - 1) ] # median for whole image medianT = vals[len(vals) // 2] # Clip ends to align class 1 and class 2 variables: # The last value of `weight1`/`mean1` should pair with zero values in # `weight2`/`mean2`, which do not exist. variance = [ weight1[i] * (median1[i] - medianT)**2 + weight2[i + 1] * (median2[i] - medianT)**2 for i in range(pts - 1) ] # get index of maximum variance to index x array threshold = x[:-1][variance.index(max(variance))] return threshold
def threshold_otsu_mode(datafield, pts=256): """ Compute Otsu's threshold with median classifier (histogram mode). Parameters ---------- datafield: gwy.DataField Datafield over which threshold will be computed. pts: int Number of points in histogram. Default 256. Returns ------- threshold: float """ # number of pts for histogram dl = gwy.DataLine(pts, 0, True) # compute z-scale histogram from image datafield.dh(dl, pts) # sort out hist data dx = dl.get_real() / dl.get_res() # pixel spacing in data line offset = dl.get_offset() # dataline offset, ie. 0 index point value in x x = [(i * dx) + offset for i in range(pts)] # construct bin locations y = dl.get_data() # get histogram values weights = dl.duplicate() weights.cumulate() # calculate cdf weights.multiply(dx) # make sure cdf sums to 1 weights = weights.get_data() # get cdf data as list # holder lists for modal values at different thresholds mode1 = [] mode2 = [] modeT = x[y.index(dl.get_max())] # get modal value for distribution # for each possible threshold value in histogram for i in range(1, pts): mode1.append(x[y.index(dl.part_extract(0, i).get_max())]) mode2.append(x[i + y[i:].index(dl.part_extract(i, pts - i).get_max())]) # calculate intraclass variance depending on the thresholds used variance = [] for i in range(len(mode1)): # should be same as mode2, ie. pts-1 variance.append(weights[:-1][i] * (mode1[i] - modeT)**2 + (1 - weights[1:][i]) * (mode2[i] - modeT)**2) # get index of maximum variance to index x array threshold = x[:-1][variance.index(max(variance))] return threshold
def line_correct_median(data): """ corrected = line_correct_median(data) Does a median line correction on the passed gwy.DataField. """ xres = data.get_xres() yres = data.get_yres() line = gwy.DataLine(xres,1.0,False) modi = gwy.DataLine(yres,1.0,False) for i in range(yres): data.get_row(line,i) median = line.get_median() modi.set_val(i,median) median = modi.get_median() for i in range(yres): data.area_add(0, i, xres, 1, median - modi.get_val(i)) return data