Skip to content

Floc-Imaging-and-Image-Processing/flocpy

Repository files navigation

import flocpy
import os
import glob
import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

Preparing the data

The floc identification software operates on a sorted list of images. Each element in the list should be a full path to an image file.

paths = flocpy.testdata_paths()
imgset1_flist = glob.glob(os.path.join(paths[0], '*.bmp')) # image set 1
imgset2_flist = glob.glob(os.path.join(paths[1], '*.png')) # image set 2

print(imgset1_flist[0])
c:\users\tashl\onedrive\documents\github\flocpy\flocpy\testdata\imgset1\023.bmp

If the files are conveniently named, you can use

sorted_flist = sorted(flist)
sorted_flist_1 = sorted(imgset1_flist)

for f in sorted_flist_1:
    print(os.path.basename(f))
023.bmp
024.bmp
025.bmp
026.bmp
027.bmp
028.bmp
029.bmp
030.bmp

Otherwise, it's best to define a custom function to facilitate sorting. In this case, we sort by a date and time encoded in the filename.

def custom_datetime(fpath):
    dtprefix = 'img-'
    i0 = len(dtprefix)
    dtlen = 14
    fmt = '%m%d%Y%H%M%S'
    return dt.datetime.strptime(os.path.basename(fpath)[i0:i0+dtlen],fmt)

sorted_flist_2 = sorted(imgset2_flist, key=custom_datetime)

for f in sorted_flist_2:
    print(os.path.basename(f))
img-01272022234452-11395.png
img-01272022234544-11400.png
img-01272022234646-11406.png

Running the floc identification algorithm

To perform the analysis, use the identify_flocs function.

Required arguments:

  • flist: A sorted list of flocs (created above)

Optional arguments:

  • resolution: A scale factor for the pixels. In these examples, there are 0.95 microns per pixel.
  • min_area: Ignores flocs that are smaller than a specified area (in specified units). The default value of zero will save all flocs regardless of size
  • max_edgewidth: A threshold parameter for identifying out of focus flocs. Quantifies the distance over which the transition from bacgkround color to floc color is spread averaged over the perimeter of the floc. Shorter edgewidths are more focused. The default value of Inf will save all flocs regardless of focus
  • extra_params: A list of parameters to save in addition to area and edgewidth. See the documentation for skimage.measure.regionprops for a list of options.
  • index: Choose which images in the list to process. Default value is None, which will process all images. If index is an integer, only one image is processed and the function returns relevant outputs. If index is a list of integers or None, function returns None
  • save: Boolean, if true, output is saved as .csv files that are named identically to images
  • return_data: Boolean, if True, results are returned as a list of floc objects. Note that this will cause memory issues if analyzing more than a few images
  • njobs: int, how many cores to use simultaneously. If njobs>1, parallel processing is performed using joblib
  • report_progress: Boolean. True prints progress to console.
# Run on image set 1:
out1 = flocpy.identify_flocs(sorted_flist_1,
                            resolution=0.95, 
                            min_diameter=0, 
                            max_edgewidth=np.inf,
                            extra_params=[], 
                            index=None,
                            save=False,
                            return_data=True,
                            n_jobs=2,
                            report_progress=True)
[Parallel(n_jobs=2)]: Using backend LokyBackend with 2 concurrent workers.
[Parallel(n_jobs=2)]: Done   1 tasks      | elapsed:   13.0s
[Parallel(n_jobs=2)]: Done   4 tasks      | elapsed:   16.0s
[Parallel(n_jobs=2)]: Done   6 out of   8 | elapsed:   18.4s remaining:    6.1s
[Parallel(n_jobs=2)]: Done   8 out of   8 | elapsed:   21.1s remaining:    0.0s
[Parallel(n_jobs=2)]: Done   8 out of   8 | elapsed:   21.1s finished
# Visualize results

fig, ax = plt.subplots(figsize=(14, 8), nrows=2, ncols=2)
ax[0,0].axis('off')
ax[1,0].axis('off')
ax[0,1].axis('off')
ax[1,1].axis('off')

imgix = 4

ax[0,0].set_title('Raw Image')
out1[imgix].plot_segmentation(ax[0,0], use_raw_img=True, show_overlay=False, show_boxes=False, 
                         box_color='k', box_thickness=1)

ax[0,1].set_title('Preprocessed Image')
out1[imgix].plot_segmentation(ax[0,1], use_raw_img=False, show_overlay=False, show_boxes=False, 
                         box_color='k', box_thickness=1)

ax[1,0].set_title('Segmented Image')
out1[imgix].plot_segmentation(ax[1,0], use_raw_img=False, show_overlay=True, show_boxes=False, 
                         box_color='k', box_thickness=1)


ax[1,1].set_title('Flocs that meet area and focus criteria')
out1[imgix].plot_segmentation(ax[1,1], min_diameter=10, max_edgewidth=10, use_raw_img=False, show_overlay=False, show_boxes=True, 
                         box_color='r', box_thickness=1)

fig.patch.set_facecolor('white')
plt.tight_layout()

png

# run on image set 2
out2 = flocpy.identify_flocs(sorted_flist_2,
                            resolution=0.95, 
                            min_diameter=0, 
                            max_edgewidth=np.inf,
                            extra_params=[], 
                            index=None,
                            save=False,
                            return_data=True,
                            n_jobs=2,
                            report_progress=True)
[Parallel(n_jobs=2)]: Using backend LokyBackend with 2 concurrent workers.
[Parallel(n_jobs=2)]: Done   3 out of   3 | elapsed:   38.6s remaining:    0.0s
[Parallel(n_jobs=2)]: Done   3 out of   3 | elapsed:   38.6s finished
# visualize results
fig, ax = plt.subplots(figsize=(16, 12), nrows=2, ncols=2)

ax[0,0].axis('off')
ax[1,0].axis('off')
ax[0,1].axis('off')
ax[1,1].axis('off')

ax[0,0].set_title('Raw Image')
out2[2].plot_segmentation(ax[0,0], use_raw_img=True, show_overlay=False, show_boxes=False)

ax[0,1].set_title('Preprocessed Image')
out2[2].plot_segmentation(ax[0,1], use_raw_img=False, show_overlay=False, show_boxes=False)

ax[1,0].set_title('Segmented Image')
out2[2].plot_segmentation(ax[1,0], use_raw_img=False, show_overlay=True, show_boxes=False)


ax[1,1].set_title('Flocs that meet area and focus criteria')
out2[2].plot_segmentation(ax[1,1], min_diameter=10, max_edgewidth=4, use_raw_img=False, show_overlay=False, show_boxes=True, 
                         box_color='r', box_thickness=1)

fig.patch.set_facecolor('white')
plt.tight_layout()

png

timeseries_flist = glob.glob(os.path.join(paths[1], '*.csv'))

sorted_flist_timeseries = sorted(timeseries_flist, key=custom_datetime)

for f in sorted_flist_timeseries[:3]:
    print(os.path.basename(f))
img-01272022234442-11394.csv
img-01272022234452-11395.csv
img-01272022234503-11396.csv
tlist = [custom_datetime(os.path.basename(f)) for f in sorted_flist_timeseries]
for t in tlist[:3]:
    print(t)
2022-01-27 23:44:42
2022-01-27 23:44:52
2022-01-27 23:45:03
focal_range = 2000 # microns
w_frame = 4000 * 0.95 # 4000 pixels * 0.95 microns per pixel
l_frame = 3000 * 0.95 # 3000 pixels * 0.95 microns per pixel
a_frame = w_frame * l_frame
    
rhos_mgl = 2650000 #sediment density in mg/l

flocstats_obj = flocpy.calculate_summarystats(sorted_flist_timeseries, frame_area=a_frame, focal_range=focal_range,
                                              min_floc_diameter=10, max_edgewidth=4)

percentiles = np.array([0.1, 1, 2.5, 10, 16, 25, 36, 50, 64, 75, 84, 90, 97.5, 99, 99.9])
table_dict = flocstats_obj.get_flocstats_table(method='all', percentile=percentiles)
floc_dataframe = pd.DataFrame(table_dict)
floc_dataframe.set_index('index', inplace=True)
Loading data


100%|██████████████████████████████████████████████████████████████████████████████████| 19/19 [00:00<00:00, 60.10it/s]
floc_dataframe
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Cs Df_0.1 Df_1.0 Df_2.5 Df_10.0 Df_16.0 Df_25.0 Df_36.0 Df_50.0 Df_64.0 Df_75.0 Df_84.0 Df_90.0 Df_97.5 Df_99.0 Df_99.9
index
0 244.641986 10.281881 12.638224 15.097269 22.73971 27.308699 33.005235 39.426682 47.699218 56.525374 64.710353 72.62339 78.942068 96.876102 100.595838 116.628579
Dfloc = floc_dataframe.iloc[0,1:].to_numpy()

fig, ax = plt.subplots()
ax.plot(Dfloc, percentiles, marker='o')
ax.set_ylim(0, 100)
ax.set_xlim(1e1, 2e2)


ax.set_xscale('log')
ax.set_xticks([10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200])
ax.set_xticklabels([10, 20, 30, 40, 50, 60, '', 80, '', 100, 200])

ax.set_ylabel('% finer by mass')
ax.set_xlabel(r'Floc Diameter ($\mu$m)')

fig.patch.set_facecolor('white')

png

table_dict = flocstats_obj.get_flocstats_table(index=tlist, method='frame', percentile=[16,50,84])
floc_dataframe = pd.DataFrame(table_dict)
floc_dataframe.set_index('index', inplace=True)
floc_dataframe
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Cs Df_16 Df_50 Df_84
index
0 217.569729 25.793956 44.578975 64.273569
1 253.488955 27.497399 50.547275 74.029477
2 270.600607 27.733509 47.647773 66.883084
3 259.021484 26.410717 47.432775 71.669437
4 240.219236 26.762231 53.082091 82.394202
5 253.839165 27.907406 47.055850 64.351515
6 243.551511 27.681302 46.573389 72.909784
7 255.598728 28.096811 48.991445 67.221932
8 224.657981 26.444495 44.244575 67.828142
9 240.816866 25.560399 48.158206 73.106468
10 258.467996 26.796867 47.755848 81.379993
11 256.799830 28.847548 49.171886 67.951771
12 274.492437 27.664109 47.503516 72.072222
13 184.158931 26.323117 44.441520 60.798018
14 226.819169 26.541093 45.137240 79.294132
15 279.418582 28.226286 49.958806 72.949866
16 238.396805 28.302398 45.984463 78.343901
17 232.289381 28.300562 48.408588 70.510703
18 237.990339 26.009581 51.142155 71.572765
fig, ax = plt.subplots()
ax.plot(floc_dataframe.Df_50, marker='o')
ax.set_xlabel('Frame number')
ax.set_xticks(np.arange(0, 19, 3))
ax.set_ylabel(r'Median Floc Diameter ($\mu$m)')
fig.patch.set_facecolor('white')

png

About

mud floc image processing tools

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages