Spaces:
Sleeping
Sleeping
v1
Browse files- .gitattributes +3 -0
- __pycache__/funcs.cpython-311.pyc +0 -0
- app.py +130 -0
- examples/IMG_0202_lr.JPG +3 -0
- examples/IMG_0229_lr.JPG +3 -0
- examples/IMG_0249_lr.JPG +3 -0
- examples/IMG_0254_lr.JPG +3 -0
- examples/IMG_1577_250microns_lr.jpg +3 -0
- examples/IMG_1582_500microns_lr.jpg +3 -0
- examples/IMG_1586_710microns_lr.jpg +3 -0
- examples/IMG_1592_1400microns_lr.jpg +3 -0
- freqs_bins.csv +171 -0
- funcs.py +213 -0
- percentiles.csv +4 -0
- requirements.txt +6 -0
- stats.csv +5 -0
.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
|
examples/IMG_0229_lr.JPG
ADDED
Git LFS Details
|
examples/IMG_0249_lr.JPG
ADDED
Git LFS Details
|
examples/IMG_0254_lr.JPG
ADDED
Git LFS Details
|
examples/IMG_1577_250microns_lr.jpg
ADDED
Git LFS Details
|
examples/IMG_1582_500microns_lr.jpg
ADDED
Git LFS Details
|
examples/IMG_1586_710microns_lr.jpg
ADDED
Git LFS Details
|
examples/IMG_1592_1400microns_lr.jpg
ADDED
Git LFS Details
|
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
|