diff --git a/python/classify.py b/python/classify.py index be6345a..61f8fd8 100644 --- a/python/classify.py +++ b/python/classify.py @@ -9,31 +9,37 @@ import numpy import colorsys import sklearn import sklearn.metrics -from scipy import misc -from envi import envi +import scipy +import scipy.misc +import envi #generate a 2D color class map using a stack of binary class images +#input: C is a C x Y x X binary image +#output: an RGB color image with a unique color for each class def classcolor2(C): #determine the number of classes - nc = C.shape[-1] + nc = C.shape[0] + + s = C.shape[1:] + s = numpy.append(s, 3) #generate an RGB image - RGB = numpy.zeros((C.shape[0], C.shape[1], 3), dtype=numpy.ubyte) + RGB = numpy.zeros(s, dtype=numpy.ubyte) #for each class for c in range(0, nc): hsv = (c * 1.0 / nc, 1, 1) color = numpy.asarray(colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2])) * 255 - RGB[C[:, :, c], :] = color + RGB[C[c, ...], :] = color return RGB #create a function that loads a set of class images as a stack of binary masks #input: list of class image names -#output: X x Y x C stack of binary mask images +#output: C x Y x X binary image specifying class/pixel membership #example: image2class(("class_coll.bmp", "class_epith.bmp")) -def image2class(*masks): +def image2class(masks): #get num of mask file names num_masks = len(masks) @@ -42,53 +48,26 @@ def image2class(*masks): print("Usage example: image2class(('class_coll.bmp', 'class_epith.bmp'))") return - #load first mask to get dimensions -- assuming all masks have same dimensions - mask = misc.imread(masks[0], flatten=True).astype(numpy.bool) - - mask_stack = numpy.zeros((mask.shape[0], mask.shape[1], num_masks), dtype=numpy.bool) - mask_stack[:,:,0] = mask - - #load the rest of masks - for i in range(1, num_masks): - mask_stack[:,:,i] = misc.imread(masks[i], flatten=True).astype(numpy.bool) - - return mask_stack - + classimages = [] + for m in masks: + img = scipy.misc.imread(m, flatten=True).astype(numpy.bool) + classimages.append(img) -#create a set of feature/target pairs for classification -#input: envi file object, stack of class masks, list of class names -#output: feature matrix (features x pixels), target matrix (1 x pixels) -#example: generate_training(("class_coll.bmp", "class_epith.bmp"), (1, 2)) -def generate_training(filename, mask_stack): - #create envi file object - E = envi(filename) + result = numpy.stack(classimages) + sum_images = numpy.sum(result.astype(numpy.uint32), 0) - # get number of classes - C = mask_stack.shape[2] + #identify and remove redundant pixels + bad_idx = sum_images > 1 + result[:, bad_idx] = 0 - #get number of annotated pixels - num_pixels = 0 - for i in range(0,C): - num_pixels += numpy.count_nonzero(mask_stack[:,:,i]) + return result - feature_matrix = numpy.zeros((E.header.bands, num_pixels), dtype=E.header.data_type) - target_matrix = numpy.zeros((1, num_pixels)) - #load masks and append the corresponding pixels to feature matrix and labels to target_matrix - idx = 0 - for i in range(0,C): - mask = E.loadmask(mask_stack[:,:,i]) - feature_matrix[:, idx:idx + mask.shape[1]] = mask - target_matrix[idx:idx+mask.shape[1]] = (i+1) - idx += mask.shape[1] - - return feature_matrix, target_matrix - -#create a class mask stack from an X x Y x C probability image -#input: X x Y x C image giving the probability P(c |x,y) -#output: X x Y x C binary class image +#create a class mask stack from an C x Y x X probability image +#input: C x Y x X image giving the probability P(c |x,y) +#output: C x Y x X binary class image def prob2class(prob_image): - class_image = numpy.zeros_like(prob_image) + class_image = numpy.zeros(prob_image.shape, dtype=numpy.bool) #get nonzero indices nnz_idx = numpy.transpose(numpy.nonzero(numpy.sum(prob_image, axis=0))) @@ -98,8 +77,20 @@ def prob2class(prob_image): class_image[idx_max_prob, idx[0], idx[1]] = 1 return class_image + #calculate an ROC curve given a probability image and mask of "True" values -def image2roc(P, t_vals, mask=[]): +#input: +# P is a Y x X probability image specifying P(c | x,y) +# t_vals is a Y x X binary image specifying points where x,y = c +# mask is a mask specifying all pixels to be considered (positives and negatives) +# use this mask to limit analysis to regions of the image that have been classified +#output: fpr, tpr, thresholds +# fpr is the false-positive rate (x-axis of an ROC curve) +# tpr is the true-positive rate (y-axis of an ROC curve) +# thresholds stores the threshold associated with each point on the ROC curve +# +#note: the AUC can be calculated as auc = sklearn.metrics.auc(fpr, tpr) +def prob2roc(P, t_vals, mask=[]): if not P.shape == t_vals.shape: print("ERROR: the probability and mask images must be the same shape") @@ -127,3 +118,7 @@ def image2roc(P, t_vals, mask=[]): labels = numpy.concatenate((Lp, Ln)) return sklearn.metrics.roc_curve(labels, scores) + +#Function to convert a set of class labels to a matrix of neuron responses for an ANN + +#Function CNN extraction function \ No newline at end of file diff --git a/python/envi.py b/python/envi.py index 483110b..4b3f9c5 100644 --- a/python/envi.py +++ b/python/envi.py @@ -278,6 +278,25 @@ class envi: return band + #create a set of feature/target pairs for classification + #input: envi file object, stack of class masks C x Y x X + #output: feature matrix (features x pixels), target matrix (1 x pixels) + #example: generate_training(("class_coll.bmp", "class_epith.bmp"), (1, 2)) + def loadtrain(self, classimages): + + # get number of classes + C = classimages.shape[0] + + F = [] + T = [] + for c in range(0, C): + f = self.loadmask(classimages[c, :, :]) #load the feature matrix for class c + t = numpy.ones((f.shape[1])) * (c+1) #generate a target array + F.append(f) + T.append(t) + + return numpy.concatenate(F, 1).transpose(), numpy.concatenate(T) + def __del__(self): self.file.close() \ No newline at end of file -- libgit2 0.21.4