Skip to content
This repository was archived by the owner on Feb 9, 2024. It is now read-only.

Commit 11040cf

Browse files
authored
Merge pull request #13 from tinalasisi/updates
Updates
2 parents a2e3c9d + c9a4025 commit 11040cf

6 files changed

Lines changed: 256 additions & 306 deletions

File tree

README.md

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ For those who want to run the program immediately, just follow these commands in
2020
`fibermorph --demo_real_section --output_directory /Users/<UserName>/<ExistingPath>/<NewFolderName`
2121
5. Use fibermorph on your own grayscale TIFFs of longitudinal or cross-sectional hair images.
2222

23-
`fibermorph --curvature --input_directory /Users/<UserName>/<ImageFolderPath> --output_directory /Users/<UserName>/<ExistingPath>/ --window_size 0.5 --window_unit mm --resolution 132 --save_image --within_element --jobs 2`
23+
`fibermorph --curvature --input_directory /Users/<UserName>/<ImageFolderPath> --output_directory /Users/<UserName>/<ExistingPath>/ --resolution_mm 132 --jobs 2`
2424

2525
and
2626

@@ -29,36 +29,27 @@ For those who want to run the program immediately, just follow these commands in
2929

3030
## Setting up
3131
1. We recommend you download [miniconda](https://docs.conda.io/en/latest/miniconda.html) for your operating system.
32+
You may also download [Anaconda](https://docs.anaconda.com/anaconda/install/). The only difference is that Anaconda comes preloaded with more libraries (500 Mb). You won't need this to run fibermorph, so we recommend you stick to minconda which is the smaller (58 Mb) and quicker to download.
3233

33-
You may also download [Anaconda](https://docs.anaconda.com/anaconda/install/). The only difference is that Anaconda comes preloaded with more libraries (500 Mb). You won't need this to run fibermorph, so we recommend you stick to minconda which is the smaller (58 Mb) and quicker to download.
34-
35-
Whichever you choose *be sure to download the version with Python 3.X and not Python 2.X*.
36-
34+
Whichever you choose *be sure to download the version with Python 3.X and not Python 2.X*.
3735
2. Open a terminal.
38-
39-
#### Mac OS:
40-
- Open the *Terminal* application.
41-
#### Windows:
42-
- Type `miniconda` in the search box and open the application.
43-
#### Linux:
44-
- Open the *Terminal* application.
45-
36+
#### Mac OS:
37+
- Open the *Terminal* application.
38+
#### Windows:
39+
- Type `miniconda` in the search box and open the application.
40+
#### Linux:
41+
- Open the *Terminal* application.
4642
3. Now you can set up a virtual environment.
4743

48-
Create an empty conda environment, e.g. `conda create -n <fibermorph_env python=3.8` and load it `conda activate fibermorph_env`
49-
50-
You are now ready to install fibermorph!
51-
44+
Create an empty conda environment, e.g. `conda create -n <fibermorph_env python=3.8` and load it `conda activate fibermorph_env`
45+
You are now ready to install fibermorph!
5246

5347
## Install the package
5448

5549
1. After having activated your new virtual environment, you can simply run `pip install fibermorph`.
56-
57-
You can find the latest release [here](https://github.com/tinalasisi/fibermorph/) on this GitHub page and on the [fibermorph PyPI page](https://pypi.org/project/fibermorph/).
58-
50+
You can find the latest release [here](https://github.com/tinalasisi/fibermorph/) on this GitHub page and on the [fibermorph PyPI page](https://pypi.org/project/fibermorph/).
5951
2. You have successfully installed fibermorph.
60-
61-
The package is now ready for use. Enter `fibermorph -h` or `fibermorph --help` to see all the flags. You can keep reading to try out the demos and read instructions on the various modules within the package.
52+
The package is now ready for use. Enter `fibermorph -h` or `fibermorph --help` to see all the flags. You can keep reading to try out the demos and read instructions on the various modules within the package.
6253

6354
## Demo data
6455
Before using this on any of your own data, it's recommended that you test that you test whether fibermorph is working properly on your machine. There are a few `demo` modules you can use to check whether fibermorph is running correctly.
@@ -89,19 +80,19 @@ To run the demo, you will input something like:
8980
### Curvature
9081
To calculate curvature from grayscale TIFF images of hair fibers, the flag `--curvature` is used with the following flags in addition to input and output directories:
9182
```
92-
--resolution_mm Integer. Number of pixels per mm for curvature analysis.
93-
--window_size [ ...]
94-
Float or integer. Desired size for window of measurement for curvature
95-
analysis in pixels or mm (given the flag --window_unit). Default is 10.
96-
Works when the --window_unit is pixels.
97-
--window_unit {px,mm}
98-
String. Unit of measurement for window of measurement for curvature
99-
analysis. Can be 'px' (pixels) or 'mm'. Default is 'px'.
100-
-s, --save_image Default is False. Will save intermediate curvature processing images if
101-
--save_image flag is included.
102-
-W, --within_element Boolean. Default is False. Will create an additional directory with
103-
spreadsheets of raw curvature measurements for each hair if the
104-
--within_element flag is included.
83+
--resolution_mm Integer. Number of pixels per mm for curvature analysis.
84+
Default is 132.
85+
--window_size [ ...] Float or integer or None. Desired size for window of measurement
86+
for curvature analysis in pixels or mm (given
87+
the flag --window_unit). If nothing is entered, the default
88+
is None and the entire hair will be used to for the curve fitting."
89+
--window_unit {px,mm} String. Unit of measurement for window of measurement for curvature
90+
analysis. Can be 'px' (pixels) or 'mm'. Default is 'px'.
91+
-s, --save_image Default is False. Will save intermediate curvature processing images if
92+
--save_image flag is included.
93+
-W, --within_element Boolean. Default is False. Will create an additional directory with
94+
spreadsheets of raw curvature measurements for each hair if the
95+
--within_element flag is included.
10596
10697
```
10798

@@ -113,7 +104,7 @@ fibermorph --curvature --input_directory /Users/<UserName>/<ImageFolderPath> --o
113104
### Section
114105
To calculate cross-sectional properties from grayscale TIFF images of hair fibers, the flag `--section` is used with the following flags:
115106
```
116-
--resolution_mu Float. Number of pixels per micron for section analysis.
107+
--resolution_mu Float. Number of pixels per micron for section analysis. Default is 4.25.
117108
--minsize Integer. Minimum diameter in microns for sections. Default is 20.
118109
--maxsize Integer. Maximum diameter in microns for sections. Default is 150.
119110

arc_sim.py

Lines changed: 0 additions & 121 deletions
This file was deleted.

fibermorph/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.1.9"
1+
__version__ = "0.2.0"

fibermorph/demo.py

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# %% import
22

3+
import sympy
4+
5+
from skimage import draw
6+
import random
7+
from random import randint
8+
import matplotlib.pyplot as plt
9+
from sympy import geometry
10+
311
import os
412
import pathlib
513
import shutil
@@ -157,6 +165,66 @@ def validation_curv(output_location, repeats, window_size_px, resolution=1):
157165
return main_output_path
158166

159167

168+
def sim_ellipse(output_directory, im_width_px, im_height_px, min_diam_um, max_diam_um, px_per_um, angle_deg):
169+
# conversions
170+
um_per_inch = 25400
171+
dpi = int(px_per_um * um_per_inch)
172+
min_rad_um = min_diam_um / 2
173+
max_rad_um = max_diam_um / 2
174+
175+
# image size in inches
176+
im_width_inch = (im_width_px / px_per_um) / um_per_inch
177+
im_height_inch = (im_height_px / px_per_um) / um_per_inch
178+
179+
imsize_inch = im_height_inch, im_width_inch
180+
imsize_px = im_height_px, im_width_px
181+
182+
min_rad_px = min_rad_um * px_per_um
183+
max_rad_px = max_rad_um * px_per_um
184+
185+
# generate array of ones (will show up as white background)
186+
img = np.ones(imsize_px, dtype=np.uint8)
187+
188+
# generate ellipse in center of image
189+
rr, cc = draw.ellipse(im_height_px / 2, im_width_px / 2, min_rad_px, max_rad_px, shape=img.shape,
190+
rotation=np.deg2rad(angle_deg))
191+
img[rr, cc] = 0
192+
193+
fig = plt.figure(frameon=False)
194+
fig.set_size_inches(im_width_inch, im_height_inch)
195+
ax = plt.Axes(fig, [0, 0, 1, 1])
196+
ax.set_axis_off()
197+
fig.add_axes(ax)
198+
199+
p1 = geometry.Point((im_height_px / px_per_um) / 2, (im_width_px / px_per_um) / 2)
200+
e1 = geometry.Ellipse(p1, hradius=max_rad_um, vradius=min_rad_um)
201+
area = sympy.N(e1.area)
202+
eccentricity = e1.eccentricity
203+
ax.imshow(img, cmap="gray", aspect='auto')
204+
205+
jetzt = datetime.now()
206+
timestamp = jetzt.strftime("%b%d_%H%M_%S_%f")
207+
208+
name = "sim_ellipse_" + str(timestamp)
209+
210+
im_path = pathlib.Path(output_directory).joinpath("im_" + name + ".tiff")
211+
df_path = pathlib.Path(output_directory).joinpath("df_" + name + ".csv")
212+
213+
data = {'name': [name], 'area': [area], 'eccentricity': [eccentricity], 'ref_min_diam': [min_diam_um],
214+
'ref_max_diam': [max_diam_um]}
215+
216+
df = pd.DataFrame(data)
217+
218+
df.to_csv(df_path)
219+
220+
plt.ioff()
221+
fig.savefig(fname=im_path, dpi=dpi)
222+
plt.cla()
223+
plt.close()
224+
225+
return df
226+
227+
160228
def validation_section(output_location, repeats):
161229

162230
jetzt = datetime.now()
@@ -166,52 +234,28 @@ def validation_section(output_location, repeats):
166234
main_output_path = fibermorph.make_subdirectory(output_location, append_name=testname)
167235

168236
dummy_dir = fibermorph.make_subdirectory(main_output_path, append_name="ValidationData")
169-
shape_list = ["circle", "ellipse"]
170-
171-
replist = [el for el in shape_list for i in range(repeats)]
172-
173-
output_path = fibermorph.make_subdirectory(main_output_path, append_name="ValidationAnalysis")
174-
175-
for shape in tqdm(replist, desc="Generating & analyzing dummy data", position=0, unit="datasets", leave=True):
176-
# print(shape)
177-
df, img, im_path, df_path = dummy_data.dummy_data_gen(
178-
output_directory=dummy_dir,
179-
shape=shape,
180-
min_elem=1,
181-
max_elem=1,
182-
im_width=5200,
183-
im_height=3900,
184-
width=1)
185-
186-
valid_df = pd.DataFrame(df).sort_values(by=[0], axis=1)
187-
min_ax = np.asarray(valid_df)[0][0]
188-
max_ax = np.asarray(valid_df)[0][1]
189-
valid_df['ref_min'] = min_ax
190-
valid_df['ref_max'] = max_ax
191-
valid_df['ref_eccentricity'] = np.sqrt(1 - (min_ax ** 2) / (max_ax ** 2))
192-
valid_df.drop(columns=['ref_height', 'ref_width'])
193-
194-
test_df = fibermorph.analyze_section(im_path, output_path, minsize=0, maxsize=3900, resolution=1.0)
195-
196-
test_df['error_min'] = abs(valid_df['ref_min'] - test_df['min']) / valid_df['ref_min']
197-
test_df['error_max'] = abs(valid_df['ref_max'] - test_df['max']) / valid_df['ref_max']
198-
199-
test_df['error_area'] = abs(valid_df['ref_area'] - test_df['area']) / valid_df['ref_area']
200-
test_df['error_eccentricity'] = np.nan_to_num(
201-
abs(valid_df['ref_eccentricity'] - test_df['eccentricity']) / valid_df['ref_eccentricity'], posinf=0)
202-
203-
valid_df2 = valid_df.join(test_df)
204-
205-
col_list = ['error_min', 'error_max', 'error_area', 'error_eccentricity']
206-
207-
error_df = valid_df2
208-
# error_df = valid_df2[col_list]
209-
210-
im_name = im_path.stem
211-
df_path = pathlib.Path(output_path).joinpath(str(im_name) + "_errordata.csv")
212-
error_df.to_csv(df_path)
237+
238+
# create list of random variables from range
239+
def gen_ellipse_data():
240+
max_diam_um = random.uniform(50, 120)
241+
min_diam_um = random.uniform(30, max_diam_um)
242+
angle_deg = random.randint(0, 360)
243+
list = [max_diam_um, min_diam_um, angle_deg]
244+
return list
245+
246+
tempdf = [gen_ellipse_data() for i in range(repeats)]
247+
248+
gen_ellipse_df = pd.DataFrame(tempdf, columns=['max_diam_um', 'min_diam_um', 'angle_deg'])
249+
250+
df_list = []
251+
for index, row in tqdm(gen_ellipse_df.iterrows(), desc="Generating ellipses", position=0, unit="datasets", leave=True):
252+
df = sim_ellipse(dummy_dir, 5200, 3900, row['min_diam_um'], row['max_diam_um'], 4.25, row['angle_deg'])
253+
df_list.append(df)
254+
255+
sim_ellipse_sum_df = pd.concat(df_list)
213256

214-
# tqdm.write("\nResults saved as:\n{}\n\n".format(df_path))
257+
with pathlib.Path(main_output_path).joinpath("summary_" + testname + ".csv") as savename:
258+
sim_ellipse_sum_df.to_csv(savename)
215259

216260
return main_output_path
217261

0 commit comments

Comments
 (0)