Blame view

python/classify.py 4.69 KB
18368aa9   David Mayerich   added a new set o...
1
2
3
4
5
6
7
8
9
  # -*- coding: utf-8 -*-
  """
  Created on Sun Jul 23 16:04:33 2017
  
  @author: david
  """
  
  import numpy
  import colorsys
90c935e3   David Mayerich   updates
10
11
  import sklearn
  import sklearn.metrics
f275c01c   David Mayerich   finalized the pre...
12
13
14
  import scipy
  import scipy.misc
  import envi
777fef6c   David Mayerich   added digital sta...
15
  import random
18368aa9   David Mayerich   added a new set o...
16
17
  
  #generate a 2D color class map using a stack of binary class images
f275c01c   David Mayerich   finalized the pre...
18
19
  #input: C is a C x Y x X binary image
  #output: an RGB color image with a unique color for each class
71ee1c23   David Mayerich   added additional ...
20
  def class2color(C):
18368aa9   David Mayerich   added a new set o...
21
22
      
      #determine the number of classes
f275c01c   David Mayerich   finalized the pre...
23
24
25
26
      nc = C.shape[0]
      
      s = C.shape[1:]
      s = numpy.append(s, 3)
18368aa9   David Mayerich   added a new set o...
27
28
  
      #generate an RGB image
f275c01c   David Mayerich   finalized the pre...
29
      RGB = numpy.zeros(s, dtype=numpy.ubyte)
18368aa9   David Mayerich   added a new set o...
30
31
32
33
34
      
      #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
f275c01c   David Mayerich   finalized the pre...
35
          RGB[C[c, ...], :] = color
18368aa9   David Mayerich   added a new set o...
36
      
538df2a2   David Mayerich   added function de...
37
38
39
40
      return RGB
  
  #create a function that loads a set of class images as a stack of binary masks
  #input: list of class image names
f275c01c   David Mayerich   finalized the pre...
41
  #output: C x Y x X binary image specifying class/pixel membership
538df2a2   David Mayerich   added function de...
42
  #example: image2class(("class_coll.bmp", "class_epith.bmp"))
f275c01c   David Mayerich   finalized the pre...
43
  def image2class(masks):
6b2be991   sberisha   added utility fun...
44
45
46
47
48
49
50
51
      #get num of mask file names
      num_masks = len(masks)
  
      if num_masks == 0:
          print("ERROR: mask filenames not provided")
          print("Usage example: image2class(('class_coll.bmp', 'class_epith.bmp'))")
          return
  
f275c01c   David Mayerich   finalized the pre...
52
53
54
55
      classimages = []
      for m in masks:
          img = scipy.misc.imread(m, flatten=True).astype(numpy.bool)
          classimages.append(img)
538df2a2   David Mayerich   added function de...
56
  
f275c01c   David Mayerich   finalized the pre...
57
58
      result = numpy.stack(classimages)
      sum_images = numpy.sum(result.astype(numpy.uint32), 0)
6b2be991   sberisha   added utility fun...
59
  
f275c01c   David Mayerich   finalized the pre...
60
61
62
      #identify and remove redundant pixels
      bad_idx = sum_images > 1
      result[:, bad_idx] = 0
6b2be991   sberisha   added utility fun...
63
  
f275c01c   David Mayerich   finalized the pre...
64
      return result
6b2be991   sberisha   added utility fun...
65
  
6b2be991   sberisha   added utility fun...
66
  
f275c01c   David Mayerich   finalized the pre...
67
68
69
  #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
6b2be991   sberisha   added utility fun...
70
  def prob2class(prob_image):
f275c01c   David Mayerich   finalized the pre...
71
      class_image = numpy.zeros(prob_image.shape, dtype=numpy.bool)
6b2be991   sberisha   added utility fun...
72
73
      #get nonzero indices
      nnz_idx = numpy.transpose(numpy.nonzero(numpy.sum(prob_image, axis=0)))
fad1a72c   David Mayerich   merged sebastian ...
74
      
6b2be991   sberisha   added utility fun...
75
76
77
78
79
80
      #set pixel corresponding to max probability to 1
      for idx in nnz_idx:
          idx_max_prob = numpy.argmax(prob_image[:, idx[0], idx[1]])
          class_image[idx_max_prob, idx[0], idx[1]] = 1
  
      return class_image
f275c01c   David Mayerich   finalized the pre...
81
  
90c935e3   David Mayerich   updates
82
  #calculate an ROC curve given a probability image and mask of "True" values
f275c01c   David Mayerich   finalized the pre...
83
84
85
86
87
88
89
90
91
92
93
94
  #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=[]):
90c935e3   David Mayerich   updates
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
      
      if not P.shape == t_vals.shape:
          print("ERROR: the probability and mask images must be the same shape")
          return
      
      #if a mask image isn't provided, create one for the entire image
      if mask == []:
          mask = numpy.ones(t_vals.shape, dtype=numpy.bool)
      
      #create masks for the positive and negative probability scores
      mask_p = t_vals
      mask_n = mask - mask * t_vals
      
      #calculate the indices for the positive and negative scores
      idx_p = numpy.nonzero(mask_p)
      idx_n = numpy.nonzero(mask_n)
      
      Pp = P[idx_p]
      Pn = P[idx_n]
6b2be991   sberisha   added utility fun...
114
  
90c935e3   David Mayerich   updates
115
116
117
118
119
120
      Lp = numpy.ones((Pp.shape), dtype=numpy.bool)
      Ln = numpy.zeros((Pn.shape), dtype=numpy.bool)
      
      scores = numpy.concatenate((Pp, Pn))
      labels = numpy.concatenate((Lp, Ln))
      
fad1a72c   David Mayerich   merged sebastian ...
121
      return sklearn.metrics.roc_curve(labels, scores)
f275c01c   David Mayerich   finalized the pre...
122
  
71ee1c23   David Mayerich   added additional ...
123
  #convert a label image to a C x Y x X class image
777fef6c   David Mayerich   added digital sta...
124
  def label2class(L, background=[]):
71ee1c23   David Mayerich   added additional ...
125
      unique = numpy.unique(L)
777fef6c   David Mayerich   added digital sta...
126
127
128
  
      if not background == []:                                                #if a background value is specified
          unique = numpy.delete(unique, numpy.nonzero(unique == background))  #remove it from the label array
71ee1c23   David Mayerich   added additional ...
129
      s = L.shape
777fef6c   David Mayerich   added digital sta...
130
      s = numpy.append(numpy.array((len(unique))), s)
71ee1c23   David Mayerich   added additional ...
131
      C = numpy.zeros(s, dtype=numpy.bool)
777fef6c   David Mayerich   added digital sta...
132
133
      for i in range(0, len(unique)):
          C[i, :, :] = L == unique[i]
71ee1c23   David Mayerich   added additional ...
134
135
      return C
  
777fef6c   David Mayerich   added digital sta...
136
137
138
139
140
141
142
143
144
  #randomizes a given mask to include a subset of n pixels in the original
  def random_mask(M, n):
      idx = numpy.flatnonzero(M)
      new_idx = numpy.random.permutation(idx)
      new_mask = numpy.zeros(M.shape, dtype=numpy.bool)
      new_mask[numpy.unravel_index(new_idx[0:n], new_mask.shape)] = True
      return new_mask
  
  
f275c01c   David Mayerich   finalized the pre...
145
146
147
  #Function to convert a set of class labels to a matrix of neuron responses for an ANN
  
  #Function CNN extraction function