Skip to content

Commit

Permalink
release-v1.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dbuscombe-usgs committed Mar 18, 2021
1 parent 8f5b061 commit e4b7cf8
Show file tree
Hide file tree
Showing 54 changed files with 694 additions and 34 deletions.
Binary file added DefaultRandomForestClassifier_water_land.pkl.z
Binary file not shown.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,32 @@ The default colormap is plotly's G10, found [here](https://plotly.com/python/dis

(you can google search those hex codes and get a color picker view). If you have more than 10 classes, the program uses `Light24` instead. This will give you up to 24 classes. Remember to keep your class names short, so the buttons all fit on the screen!

### Example screenshots of use with example dataset

#### `doodler.py`

![Example 1](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py.png)
![Example 2](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py1.png)
![Example 3](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py2.png)
![Example 4](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py3.png)
![Example 5](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py4.png)
![Example 6](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/doodler_py5.png)


#### `refine_labels.py`

![Example 1](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/refine_py.png)
![Example 2](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/refine_py1.png)


#### `predict_folder.py`

![Example 1](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/predict_py.png)
![Example 2](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/predict_py1.png)
![Example 3](https://raw.githubusercontent.com/dbuscombe-usgs/dash_doodler/main/assets/logos/predict_py2.png)



### Videos
More demonstration videos:

Expand Down Expand Up @@ -243,6 +269,20 @@ Submit a pull request through the GitHub website.
* Each setting default now displayed on control panel
* class_weight="balanced_subsample", min_samples_split=3

03/17/21
* max samples now 1e5, subsampled thereafter from all values (new and concatenated from file)
* crf_refine now loops through 5 different 'rolled' versions of the label/image combo and and an average is taken. Rolling (wot I made up) is shifting an image and unary potentials on the x axis and recomputing the label raster in the shifted position, then unrolling back and averaging down the stack of unrolled label rasters
* min_samples_split=5 in RF
* in `predict_folder.py`, now loops through 5 different 'rolled' versions of the label/image combo and a weighted average is taken
* added a 'sample' set to test `predict_folder.py`, and provide model
* provided a 'clean' yml file (no version numbers) and added tqdm as a dependency
* program now reads in default values from `src\defaults.py` or `my_defaults.py`(see below)
* program uses SIGMA_MAX and SIGMA_MIN from `src\defaults.py` or `my_defaults.py`(see below) rather than hard-coded in
* created `refine_labels.py` (not yet documented)
* program now writes and reads `my_defaults.py` that keeps track of your settings preferences
* IP address (http:https://127.0.0.1:8050/) now displayed in terminal window
* added example workflow for sample dataset


## <a name="roadmap"></a>Roadmap

Expand Down
Binary file added assets/logos/doodler_py.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/doodler_py1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/doodler_py2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/doodler_py3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/doodler_py4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/doodler_py5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/predict_py.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/predict_py1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/predict_py2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/refine_py.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logos/refine_py1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 48 additions & 11 deletions doodler.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,30 @@
##========================================================
DEFAULT_IMAGE_PATH = "assets/logos/dash-default.jpg"

DEFAULT_PEN_WIDTH = 2 # gives line width of 2^2 = 4
DEFAULT_CRF_DOWNSAMPLE = 2
DEFAULT_RF_DOWNSAMPLE = 10
DEFAULT_CRF_THETA = 40
DEFAULT_CRF_MU = 100
DEFAULT_MEDIAN_KERNEL = 3
DEFAULT_RF_NESTIMATORS = 5
DEFAULT_CRF_GTPROB = 0.9
try:
from my_defaults import *
except:
from defaults import *
finally:
DEFAULT_PEN_WIDTH = 2

DEFAULT_CRF_DOWNSAMPLE = 2

DEFAULT_RF_DOWNSAMPLE = 10

DEFAULT_CRF_THETA = 40

DEFAULT_CRF_MU = 100

DEFAULT_MEDIAN_KERNEL = 3

DEFAULT_RF_NESTIMATORS = 3

DEFAULT_CRF_GTPROB = 0.9

SIGMA_MIN = 1

SIGMA_MAX = 16

# SEG_FEATURE_TYPES = ["intensity", "edges", "texture"]

Expand Down Expand Up @@ -410,7 +426,7 @@ def download(path):
min=1,
max=30,
step=1,
value=[1, 16],
value=[SIGMA_MIN, SIGMA_MAX], #1, 16],
),

html.H6(id="rf-downsample-display"),
Expand All @@ -427,8 +443,8 @@ def download(path):
# Slider for specifying pen width
dcc.Slider(
id="rf-nestimators-slider",
min=3,
max=6,
min=1,
max=5,
step=1,
value=DEFAULT_RF_NESTIMATORS,
),
Expand Down Expand Up @@ -905,6 +921,26 @@ def update_output(

image_list_data.append(select_image_value)

try:
os.remove('my_defaults.py')
except:
pass

with open('my_defaults.py', 'a') as the_file:
the_file.write('DEFAULT_PEN_WIDTH = {}\n'.format(pen_width))
the_file.write('DEFAULT_CRF_DOWNSAMPLE = {}\n'.format(crf_downsample_value))
the_file.write('DEFAULT_RF_DOWNSAMPLE = {}\n'.format(rf_downsample_value))
the_file.write('DEFAULT_CRF_THETA = {}\n'.format(crf_theta_slider_value))
the_file.write('DEFAULT_CRF_MU = {}\n'.format(crf_mu_slider_value))
the_file.write('DEFAULT_MEDIAN_KERNEL = {}\n'.format(median_filter_value))
the_file.write('DEFAULT_RF_NESTIMATORS = {}\n'.format(n_estimators))
the_file.write('DEFAULT_CRF_GTPROB = {}\n'.format(gt_prob))
the_file.write('SIGMA_MIN = {}\n'.format(sigma_range_slider_value[0]))
the_file.write('SIGMA_MAX = {}\n'.format(sigma_range_slider_value[1]))

logging.info(datetime.now().strftime("%d-%m-%Y-%H-%M-%S"))
logging.info('my_defaults.py overwritten with new parameter settings')


if len(files) == 0:
return [
Expand Down Expand Up @@ -964,4 +1000,5 @@ def update_output(
##========================================================

if __name__ == "__main__":
print('Go to http:https://127.0.0.1:8050/ in your web browser to use Doodler')
app.run_server()#debug=True) #debug=True, port=8888)
23 changes: 23 additions & 0 deletions install/dashdoodler-clean.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: dashdoodler
channels:
- conda-forge
- defaults
dependencies:
- python
- dash-core-components
- plotly
- plotly_express
- CairoSVG
- matplotlib
- scipy
- dash
- numpy
- scikit-image
- dash-html-components
- dash-table
- Pillow
- scikit-learn
- pandas
- pydensecrf
- cairo
- tqdm
1 change: 1 addition & 0 deletions install/dashdoodler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ dependencies:
- pandas==1.0.3
- pydensecrf
- cairo
- tqdm
104 changes: 83 additions & 21 deletions predict_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from skimage.filters.rank import median
from skimage.morphology import disk
from skimage.io import imsave
from tqdm import tqdm

from tkinter import Tk
from tkinter.filedialog import askopenfilename, askdirectory
Expand All @@ -51,22 +52,33 @@
## user defined parameters
##=========================================================

multichannel = True
intensity = True
texture = True
edges = True
sigma_min=1
sigma_max=8
downsample_value = 2
crf_theta_slider_value = 10
crf_mu_slider_value = 1
crf_downsample_factor = 1
median_filter_value = 0
gt_prob = 0.9
# RF_model_file = 'RandomForestClassifier_water_land.pkl.z'
try:
from my_defaults import *
except:
from defaults import *
finally:
DEFAULT_PEN_WIDTH = 2

DEFAULT_CRF_DOWNSAMPLE = 2

DEFAULT_RF_DOWNSAMPLE = 10

DEFAULT_CRF_THETA = 40

DEFAULT_CRF_MU = 100

DEFAULT_MEDIAN_KERNEL = 3

DEFAULT_RF_NESTIMATORS = 3

DEFAULT_CRF_GTPROB = 0.9

SIGMA_MIN = 1

SIGMA_MAX = 16

Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
RF_model_file = askopenfilename(filetypes=[("Pick classifier file","R*.z")])
RF_model_file = askopenfilename(filetypes=[("Pick classifier file","*.z")])

##========================================================

Expand Down Expand Up @@ -95,27 +107,37 @@
except:
pass


Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
direc = askdirectory(title='Select directory of image samples', initialdir=os.getcwd())
files = sorted(glob(direc+'/*.jpg'))


multichannel = True
intensity = True
texture = True
edges = True
clf = load(RF_model_file) #load RF model from file

for file in files:
# DEFAULT_CRF_MU = 255
# DEFAULT_CRF_THETA = 10

for file in tqdm(files):
print("Working on %s" % (file))
img = img_to_ubyte_array(file) # read image into memory

Horig = img.shape[0]
Worig = img.shape[1]

features = extract_features(
img,
multichannel=multichannel,
intensity=intensity,
edges=edges,
texture=texture,
sigma_min=sigma_min,
sigma_max=sigma_max,
sigma_min=SIGMA_MIN,
sigma_max=SIGMA_MAX,
) # extract image features

print("Extracting features")

# use model in predictive mode
sh = features.shape
Expand All @@ -124,10 +146,50 @@
del features
result = result.reshape(sh[1:])

result, _ = crf_refine(result, img, crf_theta_slider_value, crf_mu_slider_value, crf_downsample_factor, gt_prob) #CRF refine
print("CRF refinement ")

# R = []
# for k in np.linspace(0,img.shape[0],5):
# k = int(k)
# result2, _ = crf_refine(np.roll(result,k), np.roll(img,k), DEFAULT_CRF_THETA, DEFAULT_CRF_MU, DEFAULT_CRF_DOWNSAMPLE, DEFAULT_CRF_GTPROB) #CRF refine
# result2 = np.roll(result2, -k)
# R.append(result2)

#result = np.floor(np.mean(np.dstack(R), axis=-1)).astype('uint8')

R = []; W = []
counter = 0
for k in np.linspace(0,int(img.shape[0]/5),5):
k = int(k)
result2, _ = crf_refine(np.roll(result,k), np.roll(img,k), DEFAULT_CRF_THETA, DEFAULT_CRF_MU, DEFAULT_CRF_DOWNSAMPLE, DEFAULT_CRF_GTPROB) #CRF refine

result2 = np.roll(result2, -k)
R.append(result2)
counter +=1
if k==0:
W.append(0.1)
else:
W.append(1/np.sqrt(k))

for k in np.linspace(0,int(img.shape[0]/5),5):
k = int(k)
result2, _ = crf_refine(np.roll(result,-k), np.roll(img,-k), DEFAULT_CRF_THETA, DEFAULT_CRF_MU, DEFAULT_CRF_DOWNSAMPLE, DEFAULT_CRF_GTPROB) #CRF refine

result2 = np.roll(result2, k)
R.append(result2)
counter +=1
if k==0:
W.append(0.1)
else:
W.append(1/np.sqrt(k))

#result2 = np.floor(np.mean(np.dstack(R), axis=-1)).astype('uint8')
result2 = np.round(np.average(np.dstack(R), axis=-1, weights = W)).astype('uint8')

# median filter
result = median(result, disk(median_filter_value)).astype(np.uint8)
result = median(result, disk(DEFAULT_MEDIAN_KERNEL)).astype(np.uint8)

print("Printing to file ")

imsave(file.replace(direc,results_folder).replace('.jpg','_label.png'),
label_to_colors(result-1, img[:,:,0]==0, alpha=128, colormap=class_label_colormap, color_class_offset=0, do_alpha=False))
Expand Down
Loading

0 comments on commit e4b7cf8

Please sign in to comment.