dbuscombe commited on
Commit
b0f82f7
1 Parent(s): eb2d0ce
.gitattributes CHANGED
@@ -32,3 +32,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
35
+ examples/*.* filter=lfs diff=lfs merge=lfs -text
36
+ saved_model/*.* filter=lfs diff=lfs merge=lfs -text
37
+ weights/*.* filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Daniel Buscombe, Marda Science LLC 2023
2
+ # This file contains many functions originally from Doodleverse https://github.com/Doodleverse programs
3
+
4
+ import gradio as gr
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ import matplotlib.pyplot as plt
8
+ from skimage.transform import resize
9
+ from skimage.io import imsave, imread
10
+
11
+ from skimage.filters import threshold_otsu
12
+ # from skimage.measure import EllipseModel, CircleModel, ransac
13
+ from glob import glob
14
+ import json
15
+ from transformers import TFSegformerForSemanticSegmentation
16
+
17
+ ##========================================================
18
+ def segformer(
19
+ id2label,
20
+ num_classes=2,
21
+ ):
22
+ """
23
+ https://keras.io/examples/vision/segformer/
24
+ https://huggingface.co/nvidia/mit-b0
25
+ """
26
+
27
+ label2id = {label: id for id, label in id2label.items()}
28
+ model_checkpoint = "nvidia/mit-b0"
29
+
30
+ model = TFSegformerForSemanticSegmentation.from_pretrained(
31
+ model_checkpoint,
32
+ num_labels=num_classes,
33
+ id2label=id2label,
34
+ label2id=label2id,
35
+ ignore_mismatched_sizes=True,
36
+ )
37
+ return model
38
+
39
+ ##========================================================
40
+ def fromhex(n):
41
+ """hexadecimal to integer"""
42
+ return int(n, base=16)
43
+
44
+ ##========================================================
45
+ def label_to_colors(
46
+ img,
47
+ mask,
48
+ alpha, # =128,
49
+ colormap, # =class_label_colormap, #px.colors.qualitative.G10,
50
+ color_class_offset, # =0,
51
+ do_alpha, # =True
52
+ ):
53
+ """
54
+ Take MxN matrix containing integers representing labels and return an MxNx4
55
+ matrix where each label has been replaced by a color looked up in colormap.
56
+ colormap entries must be strings like plotly.express style colormaps.
57
+ alpha is the value of the 4th channel
58
+ color_class_offset allows adding a value to the color class index to force
59
+ use of a particular range of colors in the colormap. This is useful for
60
+ example if 0 means 'no class' but we want the color of class 1 to be
61
+ colormap[0].
62
+ """
63
+
64
+ colormap = [
65
+ tuple([fromhex(h[s : s + 2]) for s in range(0, len(h), 2)])
66
+ for h in [c.replace("#", "") for c in colormap]
67
+ ]
68
+
69
+ cimg = np.zeros(img.shape[:2] + (3,), dtype="uint8")
70
+ minc = np.min(img)
71
+ maxc = np.max(img)
72
+
73
+ for c in range(minc, maxc + 1):
74
+ cimg[img == c] = colormap[(c + color_class_offset) % len(colormap)]
75
+
76
+ cimg[mask == 1] = (0, 0, 0)
77
+
78
+ if do_alpha is True:
79
+ return np.concatenate(
80
+ (cimg, alpha * np.ones(img.shape[:2] + (1,), dtype="uint8")), axis=2
81
+ )
82
+ else:
83
+ return cimg
84
+
85
+ ##====================================
86
+ def standardize(img):
87
+ # standardization using adjusted standard deviation
88
+
89
+ N = np.shape(img)[0] * np.shape(img)[1]
90
+ s = np.maximum(np.std(img), 1.0 / np.sqrt(N))
91
+ m = np.mean(img)
92
+ img = (img - m) / s
93
+ del m, s, N
94
+ #
95
+ if np.ndim(img) == 2:
96
+ img = np.dstack((img, img, img))
97
+
98
+ return img
99
+
100
+ ############################################################
101
+ ############################################################
102
+
103
+ #load model
104
+ filepath = './weights/ct_NAIP_8class_768_segformer_v3_fullmodel.h5'
105
+
106
+ configfile = filepath.replace('_fullmodel.h5','.json')
107
+ with open(configfile) as f:
108
+ config = json.load(f)
109
+
110
+ # This is how the program is able to use variables that have never been explicitly defined
111
+ for k in config.keys():
112
+ exec(k+'=config["'+k+'"]')
113
+
114
+ id2label = {}
115
+ for k in range(NCLASSES):
116
+ id2label[k]=str(k)
117
+ model = segformer(id2label,num_classes=NCLASSES)
118
+ # model.compile(optimizer='adam')
119
+
120
+ model.load_weights(filepath)
121
+
122
+
123
+ ############################################################
124
+ ############################################################
125
+
126
+ # #-----------------------------------
127
+ def est_label_multiclass(image,Mc,MODEL,TESTTIMEAUG,NCLASSES,TARGET_SIZE):
128
+
129
+ est_label = np.zeros((TARGET_SIZE[0], TARGET_SIZE[1], NCLASSES))
130
+
131
+ for counter, model in enumerate(Mc):
132
+ # heatmap = make_gradcam_heatmap(tf.expand_dims(image, 0) , model)
133
+ try:
134
+ if MODEL=='segformer':
135
+ est_label = model(tf.expand_dims(image, 0)).logits
136
+ else:
137
+ est_label = tf.squeeze(model(tf.expand_dims(image, 0)))
138
+ except:
139
+ if MODEL=='segformer':
140
+ est_label = model(tf.expand_dims(image[:,:,0], 0)).logits
141
+ else:
142
+ est_label = tf.squeeze(model(tf.expand_dims(image[:,:,0], 0)))
143
+
144
+ if TESTTIMEAUG == True:
145
+ # return the flipped prediction
146
+ if MODEL=='segformer':
147
+ est_label2 = np.flipud(
148
+ model(tf.expand_dims(np.flipud(image), 0)).logits
149
+ )
150
+ else:
151
+ est_label2 = np.flipud(
152
+ tf.squeeze(model(tf.expand_dims(np.flipud(image), 0)))
153
+ )
154
+ if MODEL=='segformer':
155
+
156
+ est_label3 = np.fliplr(
157
+ model(
158
+ tf.expand_dims(np.fliplr(image), 0)).logits
159
+ )
160
+ else:
161
+ est_label3 = np.fliplr(
162
+ tf.squeeze(model(tf.expand_dims(np.fliplr(image), 0)))
163
+ )
164
+ if MODEL=='segformer':
165
+ est_label4 = np.flipud(
166
+ np.fliplr(
167
+ tf.squeeze(model(tf.expand_dims(np.flipud(np.fliplr(image)), 0)).logits))
168
+ )
169
+ else:
170
+ est_label4 = np.flipud(
171
+ np.fliplr(
172
+ tf.squeeze(model(
173
+ tf.expand_dims(np.flipud(np.fliplr(image)), 0)))
174
+ ))
175
+
176
+ # soft voting - sum the softmax scores to return the new TTA estimated softmax scores
177
+ est_label = est_label + est_label2 + est_label3 + est_label4
178
+
179
+ return est_label, counter
180
+
181
+ # #-----------------------------------
182
+ def seg_file2tensor_3band(bigimage, TARGET_SIZE):
183
+ """
184
+ "seg_file2tensor(f)"
185
+ This function reads a jpeg image from file into a cropped and resized tensor,
186
+ for use in prediction with a trained segmentation model
187
+ INPUTS:
188
+ * f [string] file name of jpeg
189
+ OPTIONAL INPUTS: None
190
+ OUTPUTS:
191
+ * image [tensor array]: unstandardized image
192
+ GLOBAL INPUTS: TARGET_SIZE
193
+ """
194
+
195
+ smallimage = resize(
196
+ bigimage, (TARGET_SIZE[0], TARGET_SIZE[1]), preserve_range=True, clip=True
197
+ )
198
+ smallimage = np.array(smallimage)
199
+ smallimage = tf.cast(smallimage, tf.uint8)
200
+
201
+ w = tf.shape(bigimage)[0]
202
+ h = tf.shape(bigimage)[1]
203
+
204
+ return smallimage, w, h, bigimage
205
+
206
+ # #-----------------------------------
207
+ def get_image(f,N_DATA_BANDS,TARGET_SIZE,MODEL):
208
+ image, w, h, bigimage = seg_file2tensor_3band(f, TARGET_SIZE)
209
+ image = standardize(image.numpy()).squeeze()
210
+
211
+ if MODEL=='segformer':
212
+ if np.ndim(image)==2:
213
+ image = np.dstack((image, image, image))
214
+ image = tf.transpose(image, (2, 0, 1))
215
+
216
+ return image, w, h, bigimage
217
+
218
+ # #-----------------------------------
219
+
220
+ #segmentation
221
+ def segment(input_img, use_tta, use_otsu, dims=(768, 768)):
222
+
223
+ if use_otsu:
224
+ print("Use Otsu threshold")
225
+ else:
226
+ print("No Otsu threshold")
227
+
228
+ if use_tta:
229
+ print("Use TTA")
230
+ else:
231
+ print("Do not use TTA")
232
+
233
+ image, w, h, bigimage = get_image(input_img,N_DATA_BANDS,TARGET_SIZE,MODEL)
234
+
235
+ est_label, counter = est_label_multiclass(image,[model],'segformer',TESTTIMEAUG,NCLASSES,TARGET_SIZE)
236
+ print(est_label.shape)
237
+
238
+ est_label /= counter + 1
239
+ # est_label cannot be float16 so convert to float32
240
+ est_label = est_label.numpy().astype('float32')
241
+
242
+ est_label = resize(est_label, (1, NCLASSES, TARGET_SIZE[0],TARGET_SIZE[1]), preserve_range=True, clip=True).squeeze()
243
+ est_label = np.transpose(est_label, (1,2,0))
244
+ est_label = resize(est_label, (w, h))
245
+ est_label = np.argmax(est_label,-1)
246
+ print(est_label.shape)
247
+
248
+ imsave("greyscale_download_me.png", est_label.astype('uint8'))
249
+
250
+ class_label_colormap = [
251
+ "#3366CC",
252
+ "#DC3912",
253
+ "#FF9900",
254
+ "#109618",
255
+ "#990099",
256
+ "#0099C6",
257
+ "#DD4477",
258
+ "#66AA00",
259
+ "#B82E2E",
260
+ "#316395",
261
+ ]
262
+
263
+ # add classes
264
+ class_label_colormap = class_label_colormap[:NCLASSES]
265
+
266
+ color_label = label_to_colors(
267
+ est_label,
268
+ input_img[:, :, 0] == 0,
269
+ alpha=128,
270
+ colormap=class_label_colormap,
271
+ color_class_offset=0,
272
+ do_alpha=False,
273
+ )
274
+
275
+ imsave("color_download_me.png", color_label)
276
+
277
+ return color_label,"greyscale_download_me.png", "color_download_me.png"
278
+
279
+ title = "Mapping sand in high-res. imagery"
280
+ description = "This simple model demonstration segments NAIP RGB (visible spectrum) imagery into the following classes:1. water (unbroken water); 2. whitewater (surf, active wave breaking); 3. sediment (natural deposits of sand. gravel, mud, etc), 4. other_bare_natural_terrain, 5. marsh_vegetation, 6. terrestrial_vegetation, 7. agricultural, 8. development. Please note that, ordinarily, ensemble models are used in predictive mode. Here, we are using just one model, i.e. without ensembling. Allows upload of 3-band imagery in jpg format and download of label imagery only one at a time. "
281
+
282
+ examples= [[l] for l in glob('examples/*.jpg')]
283
+
284
+
285
+ inp = gr.Image()
286
+ out1 = gr.Image(type='numpy')
287
+ # out2 = gr.Plot(type='matplotlib')
288
+ out3 = gr.File()
289
+ out4 = gr.File()
290
+
291
+ inp2 = gr.inputs.Checkbox(default=False, label="Use TTA")
292
+ inp3 = gr.inputs.Checkbox(default=False, label="Use Otsu")
293
+
294
+ Segapp = gr.Interface(segment, [inp, inp2, inp3],
295
+ [out1, out3, out4], #out2
296
+ title = title, description = description, examples=examples,
297
+ theme="grass")
298
+
299
+ Segapp.launch(enable_queue=True)
examples/merged_multispectral2020_01_01.jpg ADDED

Git LFS Details

  • SHA256: 840f0e6d8f6be3e4f283fdbe27b4de3c45fbc7748ee6087f92da0147dfbf030c
  • Pointer size: 131 Bytes
  • Size of remote file: 121 kB
examples/merged_multispectral2020_01_07.jpg ADDED

Git LFS Details

  • SHA256: 6bdd3f18ac9f05573cd67bfd8afcd0a2d59e36885f271692e5f8329c4d8516eb
  • Pointer size: 130 Bytes
  • Size of remote file: 64.9 kB
examples/merged_multispectral2020_02_02.jpg ADDED

Git LFS Details

  • SHA256: 8d83846b4c117e22cbc478bf55a59254832defd535b97e44712f15fa93424134
  • Pointer size: 130 Bytes
  • Size of remote file: 88.4 kB
examples/merged_multispectral2020_02_07.jpg ADDED

Git LFS Details

  • SHA256: bf62a6e448e4d8e6542c5405bc29e53881f68e179c4697971b4ab6fa16104c3a
  • Pointer size: 130 Bytes
  • Size of remote file: 50.8 kB
examples/merged_multispectral2020_03_01.jpg ADDED

Git LFS Details

  • SHA256: f3c4ca1a9d88732d2cf93ec29b26187655ecfd8f3d8dc2ebd0414b4b7cd4d20e
  • Pointer size: 130 Bytes
  • Size of remote file: 85.4 kB
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ tensorflow
2
+ numpy
3
+ matplotlib
4
+ scikit-image
saved_model/fingerprint.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ae6730b009fd77f1e46807c2ee12ba1143a1fc59832d16f9f026469b05ea8b09
3
+ size 54
saved_model/keras_metadata.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e84dbac1fea059545ab52f543cf176adc979cb775d5d1a003b36ad660d2d4299
3
+ size 213263
saved_model/saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c67a7d393f6f32342ecbd2560d441bf6b90824ed47855739765e94e84cb2a721
3
+ size 1747465
saved_model/variables/variables.data-00000-of-00001 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:32048a7a37bbc7352f99bc7a39f8887144826586f2aae64283dfff033ca31b82
3
+ size 23041692
saved_model/variables/variables.index ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:57d4f18c722ca864d367777fffc90319c915d2b2ae399d31df2b6ea510c00fec
3
+ size 10865
weights/classes.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2e61e6a53db3cd1d6fe2c89564ee602fce97918fee756e9b7e1216b4ab966014
3
+ size 117
weights/ct_NAIP_8class_768_segformer_v3.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37fba597e45e53dea49df15dfabafcff050709101486452f26ff86f3218d49d9
3
+ size 1094
weights/ct_NAIP_8class_768_segformer_v3_fullmodel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4de3f579bc2df09e6beb0592a40b62e86c8752058edf8e10ae936da32602b027
3
+ size 15139720
weights/ct_NAIP_8class_768_segformer_v3_modelcard.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4f360c3022dfbd785b9f8c689560a5dbb3bd73c314ffdc9e907a16b26190c586
3
+ size 2228