Commit f275c01cd45055b03de7194d7a4eae38b24938ee

Authored by David Mayerich
1 parent fad1a72c

finalized the preliminary functions for classification

Showing 2 changed files with 63 additions and 49 deletions   Show diff stats
python/classify.py
... ... @@ -9,31 +9,37 @@ import numpy
9 9 import colorsys
10 10 import sklearn
11 11 import sklearn.metrics
12   -from scipy import misc
13   -from envi import envi
  12 +import scipy
  13 +import scipy.misc
  14 +import envi
14 15  
15 16 #generate a 2D color class map using a stack of binary class images
  17 +#input: C is a C x Y x X binary image
  18 +#output: an RGB color image with a unique color for each class
16 19 def classcolor2(C):
17 20  
18 21 #determine the number of classes
19   - nc = C.shape[-1]
  22 + nc = C.shape[0]
  23 +
  24 + s = C.shape[1:]
  25 + s = numpy.append(s, 3)
20 26  
21 27 #generate an RGB image
22   - RGB = numpy.zeros((C.shape[0], C.shape[1], 3), dtype=numpy.ubyte)
  28 + RGB = numpy.zeros(s, dtype=numpy.ubyte)
23 29  
24 30 #for each class
25 31 for c in range(0, nc):
26 32 hsv = (c * 1.0 / nc, 1, 1)
27 33 color = numpy.asarray(colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2])) * 255
28   - RGB[C[:, :, c], :] = color
  34 + RGB[C[c, ...], :] = color
29 35  
30 36 return RGB
31 37  
32 38 #create a function that loads a set of class images as a stack of binary masks
33 39 #input: list of class image names
34   -#output: X x Y x C stack of binary mask images
  40 +#output: C x Y x X binary image specifying class/pixel membership
35 41 #example: image2class(("class_coll.bmp", "class_epith.bmp"))
36   -def image2class(*masks):
  42 +def image2class(masks):
37 43 #get num of mask file names
38 44 num_masks = len(masks)
39 45  
... ... @@ -42,53 +48,26 @@ def image2class(*masks):
42 48 print("Usage example: image2class(('class_coll.bmp', 'class_epith.bmp'))")
43 49 return
44 50  
45   - #load first mask to get dimensions -- assuming all masks have same dimensions
46   - mask = misc.imread(masks[0], flatten=True).astype(numpy.bool)
47   -
48   - mask_stack = numpy.zeros((mask.shape[0], mask.shape[1], num_masks), dtype=numpy.bool)
49   - mask_stack[:,:,0] = mask
50   -
51   - #load the rest of masks
52   - for i in range(1, num_masks):
53   - mask_stack[:,:,i] = misc.imread(masks[i], flatten=True).astype(numpy.bool)
54   -
55   - return mask_stack
56   -
  51 + classimages = []
  52 + for m in masks:
  53 + img = scipy.misc.imread(m, flatten=True).astype(numpy.bool)
  54 + classimages.append(img)
57 55  
58   -#create a set of feature/target pairs for classification
59   -#input: envi file object, stack of class masks, list of class names
60   -#output: feature matrix (features x pixels), target matrix (1 x pixels)
61   -#example: generate_training(("class_coll.bmp", "class_epith.bmp"), (1, 2))
62   -def generate_training(filename, mask_stack):
63   - #create envi file object
64   - E = envi(filename)
  56 + result = numpy.stack(classimages)
  57 + sum_images = numpy.sum(result.astype(numpy.uint32), 0)
65 58  
66   - # get number of classes
67   - C = mask_stack.shape[2]
  59 + #identify and remove redundant pixels
  60 + bad_idx = sum_images > 1
  61 + result[:, bad_idx] = 0
68 62  
69   - #get number of annotated pixels
70   - num_pixels = 0
71   - for i in range(0,C):
72   - num_pixels += numpy.count_nonzero(mask_stack[:,:,i])
  63 + return result
73 64  
74   - feature_matrix = numpy.zeros((E.header.bands, num_pixels), dtype=E.header.data_type)
75   - target_matrix = numpy.zeros((1, num_pixels))
76 65  
77   - #load masks and append the corresponding pixels to feature matrix and labels to target_matrix
78   - idx = 0
79   - for i in range(0,C):
80   - mask = E.loadmask(mask_stack[:,:,i])
81   - feature_matrix[:, idx:idx + mask.shape[1]] = mask
82   - target_matrix[idx:idx+mask.shape[1]] = (i+1)
83   - idx += mask.shape[1]
84   -
85   - return feature_matrix, target_matrix
86   -
87   -#create a class mask stack from an X x Y x C probability image
88   -#input: X x Y x C image giving the probability P(c |x,y)
89   -#output: X x Y x C binary class image
  66 +#create a class mask stack from an C x Y x X probability image
  67 +#input: C x Y x X image giving the probability P(c |x,y)
  68 +#output: C x Y x X binary class image
90 69 def prob2class(prob_image):
91   - class_image = numpy.zeros_like(prob_image)
  70 + class_image = numpy.zeros(prob_image.shape, dtype=numpy.bool)
92 71 #get nonzero indices
93 72 nnz_idx = numpy.transpose(numpy.nonzero(numpy.sum(prob_image, axis=0)))
94 73  
... ... @@ -98,8 +77,20 @@ def prob2class(prob_image):
98 77 class_image[idx_max_prob, idx[0], idx[1]] = 1
99 78  
100 79 return class_image
  80 +
101 81 #calculate an ROC curve given a probability image and mask of "True" values
102   -def image2roc(P, t_vals, mask=[]):
  82 +#input:
  83 +# P is a Y x X probability image specifying P(c | x,y)
  84 +# t_vals is a Y x X binary image specifying points where x,y = c
  85 +# mask is a mask specifying all pixels to be considered (positives and negatives)
  86 +# use this mask to limit analysis to regions of the image that have been classified
  87 +#output: fpr, tpr, thresholds
  88 +# fpr is the false-positive rate (x-axis of an ROC curve)
  89 +# tpr is the true-positive rate (y-axis of an ROC curve)
  90 +# thresholds stores the threshold associated with each point on the ROC curve
  91 +#
  92 +#note: the AUC can be calculated as auc = sklearn.metrics.auc(fpr, tpr)
  93 +def prob2roc(P, t_vals, mask=[]):
103 94  
104 95 if not P.shape == t_vals.shape:
105 96 print("ERROR: the probability and mask images must be the same shape")
... ... @@ -127,3 +118,7 @@ def image2roc(P, t_vals, mask=[]):
127 118 labels = numpy.concatenate((Lp, Ln))
128 119  
129 120 return sklearn.metrics.roc_curve(labels, scores)
  121 +
  122 +#Function to convert a set of class labels to a matrix of neuron responses for an ANN
  123 +
  124 +#Function CNN extraction function
130 125 \ No newline at end of file
... ...
python/envi.py
... ... @@ -278,6 +278,25 @@ class envi:
278 278  
279 279 return band
280 280  
  281 + #create a set of feature/target pairs for classification
  282 + #input: envi file object, stack of class masks C x Y x X
  283 + #output: feature matrix (features x pixels), target matrix (1 x pixels)
  284 + #example: generate_training(("class_coll.bmp", "class_epith.bmp"), (1, 2))
  285 + def loadtrain(self, classimages):
  286 +
  287 + # get number of classes
  288 + C = classimages.shape[0]
  289 +
  290 + F = []
  291 + T = []
  292 + for c in range(0, C):
  293 + f = self.loadmask(classimages[c, :, :]) #load the feature matrix for class c
  294 + t = numpy.ones((f.shape[1])) * (c+1) #generate a target array
  295 + F.append(f)
  296 + T.append(t)
  297 +
  298 + return numpy.concatenate(F, 1).transpose(), numpy.concatenate(T)
  299 +
281 300  
282 301 def __del__(self):
283 302 self.file.close()
284 303 \ No newline at end of file
... ...