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,31 +9,37 @@ import numpy
9 import colorsys 9 import colorsys
10 import sklearn 10 import sklearn
11 import sklearn.metrics 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 #generate a 2D color class map using a stack of binary class images 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 def classcolor2(C): 19 def classcolor2(C):
17 20
18 #determine the number of classes 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 #generate an RGB image 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 #for each class 30 #for each class
25 for c in range(0, nc): 31 for c in range(0, nc):
26 hsv = (c * 1.0 / nc, 1, 1) 32 hsv = (c * 1.0 / nc, 1, 1)
27 color = numpy.asarray(colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2])) * 255 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 return RGB 36 return RGB
31 37
32 #create a function that loads a set of class images as a stack of binary masks 38 #create a function that loads a set of class images as a stack of binary masks
33 #input: list of class image names 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 #example: image2class(("class_coll.bmp", "class_epith.bmp")) 41 #example: image2class(("class_coll.bmp", "class_epith.bmp"))
36 -def image2class(*masks): 42 +def image2class(masks):
37 #get num of mask file names 43 #get num of mask file names
38 num_masks = len(masks) 44 num_masks = len(masks)
39 45
@@ -42,53 +48,26 @@ def image2class(*masks): @@ -42,53 +48,26 @@ def image2class(*masks):
42 print("Usage example: image2class(('class_coll.bmp', 'class_epith.bmp'))") 48 print("Usage example: image2class(('class_coll.bmp', 'class_epith.bmp'))")
43 return 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 def prob2class(prob_image): 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 #get nonzero indices 71 #get nonzero indices
93 nnz_idx = numpy.transpose(numpy.nonzero(numpy.sum(prob_image, axis=0))) 72 nnz_idx = numpy.transpose(numpy.nonzero(numpy.sum(prob_image, axis=0)))
94 73
@@ -98,8 +77,20 @@ def prob2class(prob_image): @@ -98,8 +77,20 @@ def prob2class(prob_image):
98 class_image[idx_max_prob, idx[0], idx[1]] = 1 77 class_image[idx_max_prob, idx[0], idx[1]] = 1
99 78
100 return class_image 79 return class_image
  80 +
101 #calculate an ROC curve given a probability image and mask of "True" values 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 if not P.shape == t_vals.shape: 95 if not P.shape == t_vals.shape:
105 print("ERROR: the probability and mask images must be the same shape") 96 print("ERROR: the probability and mask images must be the same shape")
@@ -127,3 +118,7 @@ def image2roc(P, t_vals, mask=[]): @@ -127,3 +118,7 @@ def image2roc(P, t_vals, mask=[]):
127 labels = numpy.concatenate((Lp, Ln)) 118 labels = numpy.concatenate((Lp, Ln))
128 119
129 return sklearn.metrics.roc_curve(labels, scores) 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 \ No newline at end of file 125 \ No newline at end of file
@@ -278,6 +278,25 @@ class envi: @@ -278,6 +278,25 @@ class envi:
278 278
279 return band 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 def __del__(self): 301 def __del__(self):
283 self.file.close() 302 self.file.close()
284 \ No newline at end of file 303 \ No newline at end of file