Project 1: Measuring size and pigmentation of isopods

In this project the goal is to measure measure phenotypic distributions of several speciemens of isopods (Asellus aquaticus) in one processing step. We also use the image-registration algorithm in detect_reference to find a reference card and automatically size and colour-correct the image.

Before

Input - Freshwater isopod, alive, photographed on a white resin-tray from a camera stand.

After

Results - Isopod shape, size and colour are extracted (and size referenced using the reference card)

Background

This workflow was used for a master’s project where we quickly needed to measure the phenotypic distribution (pigmentation [as grayscale] and size) before adding multiple batches of live isopods to a predation experiment.

phenotyping setup

Fig. 1: We photographed the isopods on a camera stand using a Canon EOS 750d DLSR with a 15-45mm lens and using LED light panels for better illumination.

Preparation

This first step creates the necessary working directories and attempts to retrive the configuration template from the online repository, or your own machine, if you downloaded the repo.

[1]:
import phenopype as pp
import os

## change working dir - will contain project folder
os.chdir(r"D:\git-repos\phenopype\phenopype-gallery\_temp")

## set project name
project_name = "project_1"

## fetch template from downloaded template repo (https://github.com/phenopype/phenopype-templates)
template_path = r"D:\git-repos\phenopype\phenopype-templates\templates\gallery\project_1.yaml"

## set directory with images
image_dir = r"D:\git-repos\phenopype\phenopype-gallery\gallery\data"
phenopype successfully imported the following plugin dependencies:
phenomorph, keras

Project

[2]:
proj = pp.Project(project_name)
--------------------------------------------
Creating a new phenopype project directory at:
D:\git-repos\phenopype\phenopype-gallery\_temp\project_1

Proceed? (y/n)
y

Project "project_1" successfully created.
--------------------------------------------
[3]:
## add all isopod-images from the data folder
proj.add_files(image_dir = image_dir, include="isopods")
--------------------------------------------
phenopype will search for image files at

D:\git-repos\phenopype\phenopype-gallery\gallery\data

using the following settings:

filetypes: ['jpg', 'JPG', 'jpeg', 'JPEG', 'tif', 'png', 'bmp'], include: isopods, exclude: [], mode: copy, recursive: False, resize: False, unique: path

Found image isopods1.jpg - phenopype-project folder 0__isopods1 created
Found image isopods2.jpg - phenopype-project folder 0__isopods2 created
Found image isopods3.jpg - phenopype-project folder 0__isopods3 created
Found image isopods4.jpg - phenopype-project folder 0__isopods4 created

Found 4 files - using all
--------------------------------------------
[4]:
## add the config template; provide a tag
proj.add_config(template_path=template_path, tag="v1", overwrite=True)
- template saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods1\pype_config_v1.yaml
- template saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods2\pype_config_v1.yaml
- template saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods3\pype_config_v1.yaml
- template saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods4\pype_config_v1.yaml
[5]:
## set the project-wide reference. the reference has its own tag, in case your project uses multiple reference cards
proj.add_reference(reference_image_path= os.path.join(image_dir,"isopods1.jpg"), reference_tag="iso-scale")
Reference set
Reference image saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\reference\iso-scale_full_image.tif
Reference image saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\reference\iso-scale_search_template.tif
Saved reference info to project attributes.
setting active global project reference to "iso-scale" for 0__isopods1 (active=True)
setting active global project reference to "iso-scale" for 0__isopods2 (active=True)
setting active global project reference to "iso-scale" for 0__isopods3 (active=True)
setting active global project reference to "iso-scale" for 0__isopods4 (active=True)
Adding a scale

Fig. 2: Draw a mask around the tray - also see https://www.phenopype.org/docs/tutorials/tutorial_2/.

[6]:
## run image processing
for path in proj.dir_paths:
    pp.Pype(path, tag="v1")

AUTOLOAD
- reference template image loaded from root directory
Stage: add annotation control args
Stage: add annotation control args
Stage: add annotation control args
Stage: add annotation control args
Stage: add annotation control args
Stage: add annotation control args
Stage: add annotation control args
Updating pype config: applying staged changes


------------+++ new pype iteration 2022-07-29 11:36:25 +++--------------




PREPROCESSING
create_mask
detect_reference
---------------------------------------------------
Reference card found with 255 keypoint matches:
template image has 27.472 pixel per mm.
current image has 27.492 pixel per mm.
= 100.074 %% of template image.
---------------------------------------------------
blur


SEGMENTATION
threshold
- decompose image: using green channel
- including pixels from 1 drawn masks
- excluding pixels from reference
morphology
detect_contour
- found 20 contours that match criteria
edit_contour
detect_contour
- found 20 contours that match criteria


MEASUREMENT
compute_shape_features
compute_texture_features
Computing texture features: 100%|██████████████████████████████████████████████████████| 20/20 [00:02<00:00,  8.15it/s]


VISUALIZATION
select_canvas
- invalid selection - defaulting to raw image
draw_contour
draw_mask
draw_reference


EXPORT
save_canvas
- image saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods1\canvas_v1.jpg.
save_annotation
- creating new annotation file
- no annotation_type selected - exporting all annotations
- writing annotations of type "mask" with id "a" to "annotations_v1.json"
- writing annotations of type "reference" with id "a" to "annotations_v1.json"
- writing annotations of type "contour" with id "a" to "annotations_v1.json"
- writing annotations of type "contour" with id "b" to "annotations_v1.json"
- writing annotations of type "drawing" with id "a" to "annotations_v1.json"
- writing annotations of type "shape_features" with id "a" to "annotations_v1.json"
- writing annotations of type "texture_features" with id "a" to "annotations_v1.json"


------------+++ finished pype iteration +++--------------
-------(End with Ctrl+Enter or re-run with Enter)--------


AUTOSHOW
- STILL UPDATING CONFIG (no content)


------------+++ new pype iteration 2022-07-29 11:37:07 +++--------------




PREPROCESSING
create_mask
- loaded existing annotation of type "mask" with ID "a": skipping (edit=False)
detect_reference
- loaded existing annotation of type "reference" with ID "a": skipping (edit=False)
blur


SEGMENTATION
threshold
- decompose image: using blue channel
- including pixels from 1 drawn masks
- excluding pixels from reference
morphology
detect_contour
- loaded existing annotation of type "contour" with ID "a": overwriting (edit=overwrite)
- found 22 contours that match criteria
edit_contour
- loaded existing annotation of type "drawing" with ID "a": skipping (edit=False)
detect_contour
- loaded existing annotation of type "contour" with ID "b": overwriting (edit=overwrite)
- found 22 contours that match criteria


MEASUREMENT
compute_shape_features
- loaded existing annotation of type "shape_features" with ID "a": overwriting (edit=overwrite)
compute_texture_features
- loaded existing annotation of type "texture_features" with ID "a": overwriting (edit=overwrite)
Computing texture features: 100%|██████████████████████████████████████████████████████| 22/22 [00:01<00:00, 11.04it/s]


VISUALIZATION
select_canvas
- invalid selection - defaulting to raw image
draw_contour
draw_mask
draw_reference


EXPORT
save_canvas
- image saved under D:\git-repos\phenopype\phenopype-gallery\_temp\project_1\data\0__isopods1\canvas_v1.jpg (overwritten).
save_annotation
- loading existing annotation file
- no annotation_type selected - exporting all annotations
- updating annotations of type "mask" with id "a" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "reference" with id "a" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "contour" with id "a" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "contour" with id "b" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "drawing" with id "a" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "shape_features" with id "a" in "annotations_v1.json" (overwrite="entry")
- updating annotations of type "texture_features" with id "a" in "annotations_v1.json" (overwrite="entry")


------------+++ finished pype iteration +++--------------
-------(End with Ctrl+Enter or re-run with Enter)--------


AUTOSHOW
An exception has occurred, use %tb to see the full traceback.

SystemExit:

TERMINATE (by user)

C:\Miniconda3\envs\pp-dev\lib\site-packages\IPython\core\interactiveshell.py:3560: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
Adding a scale

Fig. 3: Changing blocksize and constant on the thresholding algorithm has a great effect on the result. This becomes evident when looking at the binarized image, which is a great way to assess effectivness of the thresholding procedure. You can create such images directly in the Pype routine, by selecting canvas: mod in - select_canvas

[7]:
## collect results and store in folder "<project-root>/results/annotations"
proj.collect_results("v1", "annotations", "annotations")
Created D:\workspace\git-repos\phenopype\phenopype-gallery\_temp\project_1\project\results\annotations
Search string: ['annotations_v1']
Collected annotations_v1.json from 0__isopods1
0__isopods1_annotations_v1.json saved under D:\workspace\git-repos\phenopype\phenopype-gallery\_temp\project_1\project\results\annotations\0__isopods1_annotations_v1.json.
Collected annotations_v1.json from 0__isopods2
0__isopods2_annotations_v1.json saved under D:\workspace\git-repos\phenopype\phenopype-gallery\_temp\project_1\project\results\annotations\0__isopods2_annotations_v1.json.
Collected annotations_v1.json from 0__isopods3
0__isopods3_annotations_v1.json saved under D:\workspace\git-repos\phenopype\phenopype-gallery\_temp\project_1\project\results\annotations\0__isopods3_annotations_v1.json.
Collected annotations_v1.json from 0__isopods4
0__isopods4_annotations_v1.json saved under D:\workspace\git-repos\phenopype\phenopype-gallery\_temp\project_1\project\results\annotations\0__isopods4_annotations_v1.json.
[8]:
## display results
import ipyplot ## install with `pip install ipyplot`

canvas_list = []
for path in proj.dir_paths:
    canvas_list.append(pp.load_image(os.path.join(path, "canvas_v1.jpg"), mode="rgb"))

ipyplot.plot_images(canvas_list, img_width=300)
[ ]: