dbuscombe commited on
Commit
d5f12de
1 Parent(s): edd8446
.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
+ examples/*.* filter=lfs diff=lfs merge=lfs -text
37
+ examples/*.* filter=lfs diff=lfs merge=lfs -text
__pycache__/funcs.cpython-311.pyc ADDED
Binary file (10.1 kB). View file
 
app.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr Daniel Buscombe, Marda Science LLC
2
+ #
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2022, Marda Science LLC
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ import gradio as gr
26
+ import os
27
+ import pandas as pd
28
+ import matplotlib.pyplot as plt
29
+ # from skimage.transform import resize
30
+ plt.style.use('fivethirtyeight')
31
+
32
+ from funcs import *
33
+
34
+ #================================================================
35
+ def do_dgs(input_img):
36
+
37
+ maxscale=5 #20
38
+ verbose=True
39
+ x=0 #-0.5
40
+ resolution=1
41
+
42
+ w=input_img.shape[0]
43
+ h=input_img.shape[1]
44
+
45
+ # input_img = resize(input_img, (int(w/2), int(h/2)), preserve_range=True, clip=True)
46
+ # resolution = 2
47
+
48
+ data_out = dgs(input_img, resolution, maxscale, verbose, x)
49
+
50
+ ## parse out dict into three separate dictionaries
51
+ stats = dict(list(data_out.items())[:4])
52
+ percentiles = dict(list(data_out.items())[4:6])
53
+ freqs_bins = dict(list(data_out.items())[6:])
54
+
55
+ if resolution!=1:
56
+ freqs_bins['grain size bins']*=resolution
57
+ percentiles['percentile_values']*=resolution
58
+
59
+ for k in stats.keys():
60
+ stats[k] = stats[k]*resolution
61
+
62
+ tmp = list(stats.keys())
63
+ d = {}
64
+ for k in range(len(tmp)):
65
+ d.update( {tmp[k]: str(stats[tmp[k]])} )
66
+
67
+ pd.DataFrame(data=d.values(), index=d.keys()).to_csv('stats.csv')
68
+
69
+ tmp = list(percentiles.keys())
70
+ d2 = {}
71
+ for k in range(len(tmp)):
72
+ d2.update( {tmp[k]: str(percentiles[tmp[k]])} )
73
+
74
+ pd.DataFrame(data=d2.values(), index=d2.keys()).to_csv('percentiles.csv')
75
+
76
+ # write each to csv file
77
+ pd.DataFrame.from_dict(freqs_bins).to_csv('freqs_bins.csv')
78
+
79
+ # plt.clf()
80
+ fig1=plt.figure(figsize=(4,4))
81
+ plt.plot(freqs_bins['grain size bins'], freqs_bins['grain size frequencies'], lw=2)
82
+ plt.xlabel('Grain Size (pixels)')
83
+ plt.ylabel('Frequency')
84
+ plt.axvline(x=percentiles['percentile_values'][5], color="black", linestyle="--")
85
+ plt.text(percentiles['percentile_values'][5], .1, 'd50')
86
+ # plt.title('Grain Size Distribution')
87
+ # plt.xlim(np.maximum(0,stats['mean grain size']-(2*stats['grain size sorting'])), stats['mean grain size']+(2*stats['grain size sorting']))
88
+ # plt.savefig('psd.png', dpi=300, bbox_inches='tight')
89
+
90
+ # plt.clf()
91
+ fig2=plt.figure(figsize=(4,4))
92
+ plt.imshow(input_img,cmap='gray')
93
+ plt.plot([50, 50+stats['mean grain size']], [50, 50], 'r')
94
+ try:
95
+ plt.xlim(0,200)
96
+ plt.ylim(0,200)
97
+ except:
98
+ pass
99
+ plt.axis("off")
100
+
101
+ out = {}
102
+ out.update( {'mean grain size': float(str(stats['mean grain size'])[:4]) } )
103
+ out.update( {'grain size sorting': float(str(stats['grain size sorting'])[:4]) } )
104
+ out.update( {'d16': float(str(percentiles['percentile_values'][2])[:4]) } )
105
+ out.update( {'d50': float(str(percentiles['percentile_values'][5])[:4]) } )
106
+ out.update( {'d84': float(str(percentiles['percentile_values'][7])[:4]) } )
107
+
108
+ return pd.DataFrame(data=out.values(), index=out.keys()).transpose(), fig1, fig2, 'stats.csv', 'percentiles.csv', 'freqs_bins.csv'
109
+
110
+
111
+
112
+ title = "Digital Grain Size"
113
+ description = "Upload an image of sediment. Download grain size stats. Clear between images. See https://github.com/dbuscombe-usgs/pyDGS. May take a very long time for large images"
114
+
115
+
116
+ examples= [[l] for l in glob('examples/*.jpg')]
117
+
118
+ inp = gr.Image(label='Upload images one-by-one')
119
+ out1 = gr.Dataframe(label='Summary statistics', headers=["mean (px)", "sorting (px)", "d16 (px)", "d50 (px)", "d84 (px)"], type='pandas')
120
+ #out1 = gr.outputs.Image(type='numpy')
121
+ out2a = gr.Plot(label='Grain Size Distribution', type='auto') #'matplotlib')
122
+ out2b = gr.Plot(label='Red Line = Mean Grain Length', type='auto') #'matplotlib')
123
+
124
+ out4 = gr.File(label='Click to download grain size summary stats (px)')
125
+ out5 = gr.File(label='Click to download grain size percentiles (px)')
126
+ out6 = gr.File(label='Click to download grain size distribution: bins (px) and frequencies')
127
+
128
+ Segapp = gr.Interface(do_dgs, inp, [out1, out2a, out2b, out4, out5, out6], title = title, description = description, examples=examples)
129
+
130
+ Segapp.launch(enable_queue=True)
examples/IMG_0202_lr.JPG ADDED

Git LFS Details

  • SHA256: 02c8bdbabf6c57edd4889f3a63964b9d8186918811c197eae382386e489b4ffe
  • Pointer size: 131 Bytes
  • Size of remote file: 555 kB
examples/IMG_0229_lr.JPG ADDED

Git LFS Details

  • SHA256: c53135ce72619cdbcf8fae9a4b098337611c03ba6e6c723d4e9b756147ae25bb
  • Pointer size: 131 Bytes
  • Size of remote file: 815 kB
examples/IMG_0249_lr.JPG ADDED

Git LFS Details

  • SHA256: d2dca6a1eabc489ce5b6090b7007d139c1764fd799ed0aa7cfb4af4a8189301a
  • Pointer size: 131 Bytes
  • Size of remote file: 836 kB
examples/IMG_0254_lr.JPG ADDED

Git LFS Details

  • SHA256: af8a911b0b1c613d33e4358d8ee0ef2f6f795e739ed7e162b333039beaecad18
  • Pointer size: 131 Bytes
  • Size of remote file: 865 kB
examples/IMG_1577_250microns_lr.jpg ADDED

Git LFS Details

  • SHA256: d25d817a854be5147ab6ea392e56f5ab81d65fee7b9d2fdb4e6473c9dd9ad4c9
  • Pointer size: 132 Bytes
  • Size of remote file: 1.46 MB
examples/IMG_1582_500microns_lr.jpg ADDED

Git LFS Details

  • SHA256: 9e9dc077b104ff2aa9b8378d55329aa3105c19c1ecef6ef0e263c05097bbb037
  • Pointer size: 132 Bytes
  • Size of remote file: 1.31 MB
examples/IMG_1586_710microns_lr.jpg ADDED

Git LFS Details

  • SHA256: de7ec9034082bd363313c9dd42790b3b020d96e418ab96c131bde9da76ee13c1
  • Pointer size: 132 Bytes
  • Size of remote file: 1.26 MB
examples/IMG_1592_1400microns_lr.jpg ADDED

Git LFS Details

  • SHA256: 85974e0712991bef6c16bf05662fd77c98ac009a6be7e9ffa9847dc384e95dee
  • Pointer size: 132 Bytes
  • Size of remote file: 1.13 MB
freqs_bins.csv ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ,grain size frequencies,grain size bins
2
+ 0,0.0016426220390771682,1.8461538461538463
3
+ 1,0.002167585907438987,2.4615384615384617
4
+ 2,0.002668904649119935,3.0769230769230766
5
+ 3,0.0031699938478729063,3.6923076923076925
6
+ 4,0.003651220742984358,4.3076923076923075
7
+ 5,0.004126514308542332,4.923076923076923
8
+ 6,0.004609535210052074,5.538461538461538
9
+ 7,0.0050892227565306316,6.153846153846153
10
+ 8,0.0055744168004208915,6.769230769230769
11
+ 9,0.006045121494313346,7.384615384615385
12
+ 10,0.0065011214310461765,8.0
13
+ 11,0.006950538656204636,8.615384615384615
14
+ 12,0.007389333612356867,9.23076923076923
15
+ 13,0.007809496979602846,9.846153846153847
16
+ 14,0.008243336744138465,10.461538461538462
17
+ 15,0.008661944785145438,11.076923076923077
18
+ 16,0.009044087191385648,11.692307692307692
19
+ 17,0.00944831674873626,12.307692307692307
20
+ 18,0.009835436981769497,12.923076923076923
21
+ 19,0.010181128652331214,13.538461538461538
22
+ 20,0.01050415572102688,14.153846153846155
23
+ 21,0.010802845826556693,14.76923076923077
24
+ 22,0.011083779516659424,15.384615384615383
25
+ 23,0.011323672081431773,16.0
26
+ 24,0.01154374103241903,16.615384615384617
27
+ 25,0.01174549990392021,17.23076923076923
28
+ 26,0.011921139186435994,17.846153846153847
29
+ 27,0.012062611891841634,18.46153846153846
30
+ 28,0.012149605471212093,19.076923076923077
31
+ 29,0.012256719411607683,19.692307692307693
32
+ 30,0.012331703200822185,20.30769230769231
33
+ 31,0.012378469825517357,20.923076923076923
34
+ 32,0.012382949096099351,21.538461538461537
35
+ 33,0.012402253752891347,22.153846153846153
36
+ 34,0.012388518196972866,22.769230769230766
37
+ 35,0.012345729484965465,23.384615384615383
38
+ 36,0.012308219483070329,24.0
39
+ 37,0.012250705726838462,24.615384615384613
40
+ 38,0.012167377058765545,25.23076923076923
41
+ 39,0.012098696309146634,25.846153846153847
42
+ 40,0.011965261136264654,26.461538461538463
43
+ 41,0.011842219747470626,27.076923076923077
44
+ 42,0.011698744470455937,27.692307692307693
45
+ 43,0.011542259305387811,28.30769230769231
46
+ 44,0.011363379103230795,28.923076923076923
47
+ 45,0.011156752470320483,29.53846153846154
48
+ 46,0.010947912038893138,30.153846153846153
49
+ 47,0.010724109684386167,30.769230769230766
50
+ 48,0.010490633348516493,31.384615384615387
51
+ 49,0.010223843883055434,32.0
52
+ 50,0.00995192219751871,32.61538461538461
53
+ 51,0.00970494820986643,33.23076923076923
54
+ 52,0.009428785949242607,33.84615384615385
55
+ 53,0.009173145595160952,34.46153846153846
56
+ 54,0.008899741702773412,35.07692307692308
57
+ 55,0.008661039403923454,35.69230769230769
58
+ 56,0.008403869634455172,36.30769230769231
59
+ 57,0.008156783324095173,36.92307692307692
60
+ 58,0.0079269166346256,37.53846153846154
61
+ 59,0.007669992530057691,38.15384615384615
62
+ 60,0.007505031734891424,38.769230769230774
63
+ 61,0.007281079594547751,39.38461538461539
64
+ 62,0.007096595700886726,40.0
65
+ 63,0.006920991222684111,40.61538461538462
66
+ 64,0.006736086397618743,41.230769230769226
67
+ 65,0.006575650233596457,41.84615384615385
68
+ 66,0.0064181372103633404,42.46153846153846
69
+ 67,0.006274382395202138,43.07692307692307
70
+ 68,0.006141582712110023,43.69230769230769
71
+ 69,0.006008182294776169,44.30769230769231
72
+ 70,0.005885070587766238,44.92307692307693
73
+ 71,0.0057621280423813155,45.53846153846153
74
+ 72,0.005643066978396318,46.15384615384615
75
+ 73,0.005535288754723778,46.76923076923077
76
+ 74,0.005416295873642339,47.38461538461539
77
+ 75,0.005321391438623787,48.0
78
+ 76,0.005227047385243807,48.61538461538462
79
+ 77,0.005133002025558695,49.230769230769226
80
+ 78,0.005041083126273276,49.84615384615385
81
+ 79,0.004945032802174178,50.46153846153846
82
+ 80,0.004865689827376969,51.07692307692307
83
+ 81,0.004790519209525123,51.69230769230769
84
+ 82,0.00472369408648769,52.30769230769231
85
+ 83,0.004635627439684633,52.92307692307693
86
+ 84,0.004565541095126921,53.53846153846153
87
+ 85,0.004496305870199668,54.15384615384615
88
+ 86,0.004430789746276958,54.769230769230774
89
+ 87,0.004369170438953784,55.38461538461539
90
+ 88,0.004313165537727826,56.0
91
+ 89,0.004260803052558832,56.61538461538462
92
+ 90,0.004201367009515563,57.23076923076923
93
+ 91,0.004148478339295584,57.84615384615385
94
+ 92,0.004074701688990735,58.46153846153846
95
+ 93,0.0040520748074667975,59.07692307692308
96
+ 94,0.00400727588586632,59.69230769230769
97
+ 95,0.003956073673700605,60.30769230769231
98
+ 96,0.003913581667714583,60.92307692307692
99
+ 97,0.0038748269950508564,61.53846153846153
100
+ 98,0.003825921892423967,62.15384615384615
101
+ 99,0.0037973563463867908,62.769230769230774
102
+ 100,0.003745405560385463,63.38461538461539
103
+ 101,0.0037026294901179374,64.0
104
+ 102,0.00366627250047759,64.61538461538461
105
+ 103,0.0036119565983156955,65.23076923076923
106
+ 104,0.00360189208011268,65.84615384615384
107
+ 105,0.003559570569230386,66.46153846153847
108
+ 106,0.0035196429437868667,67.07692307692308
109
+ 107,0.0034877990085286346,67.6923076923077
110
+ 108,0.003457445037955179,68.3076923076923
111
+ 109,0.003424561985387016,68.92307692307692
112
+ 110,0.003392609732527566,69.53846153846153
113
+ 111,0.00336922764366803,70.15384615384616
114
+ 112,0.0033427922323019097,70.76923076923077
115
+ 113,0.0033212220795013608,71.38461538461539
116
+ 114,0.0032950670208449183,72.0
117
+ 115,0.00327952595609543,72.61538461538461
118
+ 116,0.0032654424561148598,73.23076923076923
119
+ 117,0.003242877258701247,73.84615384615384
120
+ 118,0.003232004290244402,74.46153846153845
121
+ 119,0.003220965181451411,75.07692307692308
122
+ 120,0.003212700078689291,75.6923076923077
123
+ 121,0.0032046498440294275,76.3076923076923
124
+ 122,0.0032006549619270803,76.92307692307692
125
+ 123,0.003216259993445007,77.53846153846155
126
+ 124,0.003211376135543289,78.15384615384616
127
+ 125,0.0031800941464485196,78.76923076923077
128
+ 126,0.0031904304207016933,79.38461538461539
129
+ 127,0.003196529413287816,80.0
130
+ 128,0.0032045771557983587,80.61538461538461
131
+ 129,0.003210219321174473,81.23076923076924
132
+ 130,0.0032157721848310597,81.84615384615385
133
+ 131,0.003223355288919453,82.46153846153845
134
+ 132,0.0032323883990270953,83.07692307692308
135
+ 133,0.0032426105888122185,83.6923076923077
136
+ 134,0.003250512700078592,84.3076923076923
137
+ 135,0.0032603325612916806,84.92307692307692
138
+ 136,0.0032680394631475263,85.53846153846153
139
+ 137,0.0032785397128673862,86.15384615384615
140
+ 138,0.003293319139721532,86.76923076923077
141
+ 139,0.0032984503116931093,87.38461538461539
142
+ 140,0.0033033505074822416,88.0
143
+ 141,0.003315195301571048,88.61538461538461
144
+ 142,0.0033200357101548974,89.23076923076923
145
+ 143,0.003328690924245227,89.84615384615385
146
+ 144,0.0033323933324966395,90.46153846153847
147
+ 145,0.003339397654829808,91.07692307692307
148
+ 146,0.0033409159213007664,91.6923076923077
149
+ 147,0.003347364526244621,92.3076923076923
150
+ 148,0.0033520913685139452,92.92307692307693
151
+ 149,0.0033514243713214757,93.53846153846153
152
+ 150,0.003352879546326893,94.15384615384615
153
+ 151,0.0033525735149703777,94.76923076923077
154
+ 152,0.003350254997413536,95.38461538461537
155
+ 153,0.003349566597363225,96.0
156
+ 154,0.0033452351633064693,96.61538461538463
157
+ 155,0.0033414811415823763,97.23076923076924
158
+ 156,0.003322441024870215,97.84615384615385
159
+ 157,0.003332490445771742,98.46153846153845
160
+ 158,0.0033265262827851957,99.07692307692308
161
+ 159,0.00331617847741188,99.6923076923077
162
+ 160,0.0033096442256116496,100.3076923076923
163
+ 161,0.0032994077570679646,100.92307692307692
164
+ 162,0.003289287964925445,101.53846153846155
165
+ 163,0.0032770381468205535,102.15384615384615
166
+ 164,0.003266991725648282,102.76923076923076
167
+ 165,0.0032576446351446145,103.38461538461539
168
+ 166,0.00324297091826369,104.0
169
+ 167,0.0032383175998767833,104.61538461538461
170
+ 168,0.0032074549401878236,105.23076923076924
171
+ 169,0.0032004106205451976,105.84615384615385
funcs.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr Daniel Buscombe, Marda Science LLC
2
+ #
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2022, Marda Science LLC
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ # from imageio import imread
26
+ import pywt
27
+ #from tqdm import tqdm
28
+ from skimage.restoration import denoise_wavelet, estimate_sigma
29
+ from functools import partial
30
+ # rescale_sigma=True required to silence deprecation warnings
31
+ _denoise_wavelet = partial(denoise_wavelet, rescale_sigma=True)
32
+ import numpy as np
33
+ import scipy.stats as stats
34
+ from glob import glob
35
+
36
+ def rescale(dat,mn,mx):
37
+ """
38
+ rescales an input dat between mn and mx
39
+ """
40
+ m = min(dat.flatten())
41
+ M = max(dat.flatten())
42
+ return (mx-mn)*(dat-m)/(M-m)+mn
43
+
44
+ ##====================================
45
+ def standardize(img):
46
+ img = np.array(img)
47
+ #standardization using adjusted standard deviation
48
+ N = np.shape(img)[0] * np.shape(img)[1]
49
+ s = np.maximum(np.std(img), 1.0/np.sqrt(N))
50
+ m = np.mean(img)
51
+ img = (img - m) / s
52
+ img = rescale(img, 0, 1)
53
+ del m, s, N
54
+
55
+ return img
56
+
57
+
58
+ # =========================================================
59
+ # =========================================================
60
+ def dgs(input_img, resolution=1, maxscale=4, verbose=1, x=-0.5):
61
+
62
+ #if verbose==1:
63
+ print("===========================================")
64
+ print("======DIGITAL GRAIN SIZE: WAVELET==========")
65
+ print("===========================================")
66
+ print("=CALCULATE GRAIN SIZE-DISTRIBUTION FROM AN=")
67
+ print("====IMAGE OF SEDIMENT/GRANULAR MATERIAL====")
68
+ print("===========================================")
69
+ print("======A PROGRAM BY DANIEL BUSCOMBE=========")
70
+ print("====MARDASCIENCE, FLAGSTAFF, ARIZONA=======")
71
+ print("========REVISION 4.2, APR 2022===========")
72
+ print("===========================================")
73
+
74
+ # ======= stage 1 ==========================
75
+ #read image
76
+ if verbose==1:
77
+ print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
78
+ print('Processing image ')
79
+
80
+ im = np.squeeze(input_img) # squeeze singleton dimensions
81
+ if len(np.shape(im))>3:
82
+ im = im[:, :, :3] # only keep the first 3 bands
83
+
84
+ if len(np.shape(im))==3: # if rgb, convert to grey
85
+ im = (0.299 * im[:,:,0] + 0.5870*im[:,:,1] + 0.114*im[:,:,2]).astype('uint8')
86
+
87
+ nx,ny = np.shape(im)
88
+ if nx>ny:
89
+ im=im.T
90
+
91
+ im = standardize(im)
92
+ # # ======= stage 2 ==========================
93
+ # Denoised image using default parameters of `denoise_wavelet`
94
+ filter=False
95
+
96
+ if filter:
97
+
98
+ sigma_est = estimate_sigma(im, multichannel=False, average_sigmas=True)
99
+ region = denoise_wavelet(im, multichannel=False, rescale_sigma=True,
100
+ method='VisuShrink', mode='soft', sigma=sigma_est)
101
+
102
+ else:
103
+
104
+ region = im.copy()
105
+
106
+ original = rescale(region,0,255)
107
+
108
+ nx, ny = original.shape
109
+
110
+ # ======= stage 3 ==========================
111
+ # call cwt to get particle size distribution
112
+
113
+
114
+ ## initial guess
115
+ P = []; M = []
116
+ for k in np.linspace(1,nx-1,40):
117
+ [cfs, frequencies] = pywt.cwt(original[int(k),:], np.arange(3, np.maximum(nx,ny)/maxscale, 1), 'morl' , .5)
118
+ period = 1. / frequencies
119
+ power =(abs(cfs)) ** 2
120
+ power = np.mean(np.abs(power), axis=1)/(period**2)
121
+ P.append(power)
122
+
123
+ M.append(period[np.argmax(power)])
124
+
125
+ p = np.mean(np.vstack(P), axis=0)
126
+ p = np.array(p/np.sum(p))
127
+
128
+ # get real scales by multiplying by resolution (mm/pixel)
129
+ scales = np.array(period)*resolution
130
+
131
+ print(np.sum(p*scales))
132
+ if np.sum(p*scales)>80:
133
+ x=1
134
+ maxscale=4
135
+ elif (np.sum(p*scales)<80) and (np.sum(p*scales)>60):
136
+ x=0.75
137
+ maxscale=8
138
+ elif (np.sum(p*scales)<60) and (np.sum(p*scales)>40):
139
+ x=0.5
140
+ maxscale=12
141
+ elif (np.sum(p*scales)<40) and (np.sum(p*scales)>20):
142
+ x=-0.5
143
+ maxscale=16
144
+ elif np.sum(p*scales)<20:
145
+ x=-1
146
+ maxscale=20
147
+
148
+ print("x is {}".format(x))
149
+ print("maxscale is {}".format(maxscale))
150
+
151
+ ## for real
152
+ P = []; M = []
153
+ for k in np.linspace(1,nx-1,100):
154
+ [cfs, frequencies] = pywt.cwt(original[int(k),:], np.arange(3, np.maximum(nx,ny)/maxscale, 1), 'morl' , .5)
155
+ period = 1. / frequencies
156
+ power =(abs(cfs)) ** 2
157
+ power = np.mean(np.abs(power), axis=1)/(period**2)
158
+ P.append(power)
159
+
160
+ M.append(period[np.argmax(power)])
161
+
162
+ p = np.mean(np.vstack(P), axis=0)
163
+ p = np.array(p/np.sum(p))
164
+
165
+ # get real scales by multiplying by resolution (mm/pixel)
166
+ scales = np.array(period)*resolution
167
+
168
+ srt = np.sqrt(np.sum(p*((scales-np.mean(M))**2)))
169
+
170
+ # plt.plot(scales, p,'m', lw=2)
171
+
172
+ p = p+stats.norm.pdf(scales, np.mean(M), srt/np.pi)
173
+ p = p/np.sum(p)
174
+
175
+ mnsz = np.sum(p*scales)
176
+ srt = np.sqrt(np.sum(p*((scales-mnsz)**2)))
177
+
178
+ ind =np.where(scales < (mnsz+3*srt))[0]
179
+ scales= scales[ind]
180
+ p = p[ind]
181
+ # p = np.hstack([0,p])
182
+ # scales = np.hstack([0,scales])
183
+
184
+ # area-by-number to volume-by-number
185
+ r_v = (p*scales**x) / np.sum(p*scales**x) #volume-by-weight proportion
186
+
187
+ # ======= stage 5 ==========================
188
+ # calc particle size stats
189
+
190
+ pd = np.interp([.05,.1,.16,.25,.3,.5,.75,.84,.9,.95],np.hstack((0,np.cumsum(r_v))), np.hstack((0,scales)) )
191
+ if verbose==1:
192
+ print("d50 = "+str(pd[4]))
193
+
194
+ mnsz = np.sum(r_v*scales)
195
+ if verbose==1:
196
+ print("mean size = "+str(mnsz))
197
+
198
+ srt = np.sqrt(np.sum(r_v*((scales-mnsz)**2)))
199
+ if verbose==1:
200
+ print("stdev = "+str(srt))
201
+
202
+ sk = (sum(r_v*((scales-mnsz)**3)))/(100*srt**3)
203
+ if verbose==1:
204
+ print("skewness = "+str(sk))
205
+
206
+ kurt = (sum(r_v*((scales-mnsz)**4)))/(100*srt**4)
207
+ if verbose==1:
208
+ print("kurtosis = "+str(kurt))
209
+
210
+ # ======= stage 6 ==========================
211
+ # return a dict object of stats
212
+ return {'mean grain size': mnsz, 'grain size sorting': srt, 'grain size skewness': sk, 'grain size kurtosis': kurt, 'percentiles': [.05,.1,.16,.25,.3,.5,.75,.84,.9,.95], 'percentile_values': pd, 'grain size frequencies': r_v, 'grain size bins': scales}
213
+
percentiles.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ ,0
2
+ percentiles,"[0.05, 0.1, 0.16, 0.25, 0.3, 0.5, 0.75, 0.84, 0.9, 0.95]"
3
+ percentile_values,"[ 8.42088522 12.12575912 15.64543534 20.28097679 22.76488214 33.69610315
4
+ 60.00452672 75.82437868 87.2558193 96.47342121]"
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ numpy
2
+ matplotlib
3
+ imageio
4
+ scikit-image
5
+ pywavelets
6
+ pandas
stats.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ ,0
2
+ mean grain size,42.10146327816689
3
+ grain size sorting,27.384385416408026
4
+ grain size skewness,0.007339603505687132
5
+ grain size kurtosis,0.024435709503563517