Commit f275c01cd45055b03de7194d7a4eae38b24938ee
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 | ... | ... |