Detect QR codes#

For a more detailed description see: www.phenopype.org/gallery/projects/qr-codes/

import phenopype as pp
import os 
import pandas as pd

## my root directory - modify as you see fit 
os.chdir(r"D:\science\packages\phenopype\phenopype-gallery_exec")

## set maximum size of phenopype window
pp._config.window_max_dim = 800

Make phenopype project#

Create a phenopype project (remember, Project is used to both create new projects, and load existing ones). Different phenopype projects can be useful, e.g., to process different batches of images from field seasons, perspectives, etc,. It makes sense to create them side by side in a subfolder, which I call “phenopype”. Thus, my research projects often have the following directory structure (just my way of working - this is really totally up to you):

my-project
    data                       # processed data (e.g., tables)
    data_raw                   # raw data (images, videos, etc.)
    phenopype                  # phenopype projects
    phenopype_templates        # phenopype .yaml config templates
    scripts                    # python, R, etc.
    [...]                      # manuscripts, figures, literature, etc.
proj = pp.Project(r"phenopype\qr-codes")

Add images to the project. mode="link" does not copy the raw image, but simply creates a link to save space on the harddrive.

proj.add_files(image_dir="data_raw\qr-codes", mode="link")

Add a config file for each image:

proj.add_config(template_path="phenopype_templates\qr-codes_template1.yaml", tag="v1")

Run the loop with feedback=False and phenopype will attempt to automatically detect QR codes without any interaction.

for path in proj.dir_paths: 
    p = pp.Pype(path, "v1", 
                feedback=False,             # turn off feedback for automatic mode 
                autoshow=False,             # set to False to not have to confirm the end of an iteration with CTRL+Enter
                # skip="comment",           # set to True to skip to next non-processed image 
                )

Collect the results and concatenate them to a single file, or in case of the canvas, store them to a single folder.

proj.collect_results(files=["canvas", "comment"], tag="v1", aggregate_csv=True, overwrite=True)
comments = pd.read_csv(os.path.join(proj.root_dir, "results", "comment_v1.csv"))
print(comments)

Fix failed detections#

As you can see, the approach did not always work; either because there was no QR code in the image, or it was obscured by the damselfly or shadows. You now have a couple of options:

  1. Add the argument enter_manually: True to the template and run it again. (uncomment line 6 in the provided template)

  2. Find the images where QR-code detection failed and run them again with the template for the id-tags project

## option 1
## first, edit the template: under "detect_QRcode", set "enter_manually: True" 
## then, add the new config to the project 
proj.add_config(template_path="phenopype_templates\qr-codes-template1.yml", tag="v1", overwrite=True)
## run the project again
for path in proj.dir_paths: 
    p = pp.Pype(path, "v1", 
                feedback=True,              # needs to be on now!
                autoshow=False,             # set to False to not have to confirm the end of an iteration with CTRL+Enter
                # skip="comment",           # set to True to skip to next non-processed image 
                )
## option 2 
## first, make a list
failed_img_paths = list()
## step 1 - find images where QR-code detection failed - either by looping through the project folders directly...
for path in proj.dir_paths:
    if not "annotations_v1.json" in os.listdir(path):
        failed_img_paths.append(path)
        
## ... or by finding the rows in the results file
comments = pd.read_csv(r"phenopype\qr-codes\results\comment_v1.csv")
failed_imgs = list(comments[pd.isna(comments["ID"])]["image_name"])
for img, path in zip(proj.file_names, proj.dir_paths):
    if img in failed_imgs:
        failed_img_paths.append(path)
## step 2 - give only failed image new config (can also be done using new config file (e.g., "v2"))
proj.add_config(tag="v1", subset=failed_img_paths, 
                template_path="phenopype_templates\it-tags-template1.yml", overwrite=True)
## step 3 - second run: manual ID entry
for idx, path in enumerate(failed_img_paths):
    pp.Pype(path, tag="v1", autoshow=False) #autosave=False, overwrite=True, feedback=False
proj.collect_results(files=["canvas", "comment"], tag="v1", save_suffix="fixed", aggregate_csv=True, overwrite=True)