If you have a continous data influx you may want to analyse incoming images regularly, e.g., running a script in the background that periodically invokes your processing scripts.

Example Processing Scripts

Initial Metadata Generation

if(!require('yaml')) install.packages('yaml')

photosens_write_yaml <- function(meta, path) {
  yaml::write_yaml(meta, file = path, precision = 11)
}

image_root_path <- 'archive_photo/'
meta_root_path  <- 'archive_meta/'

image_files <- list.files(image_root_path, pattern = '*.(JPG|jpg)$', recursive = TRUE, full.names = FALSE)

for(image_file in image_files) {
  # images and metadata files are stored in parallel
  # metadata file names: image_file_name.ext.yaml
  image_file_path <- file.path(image_root_path, image_file)
  meta_file_path <- file.path(meta_root_path, paste0(image_file, '.yaml'))
  
  if(file.exists(meta_file_path)) {
    cat(paste0('Skip existing  ', meta_file_path, '\n'))
  } else {
    filename <- basename(image_file)
    timetext <- substring(filename, 2, 13) # example: filename contains timestamp
    timestamp <- format(as.POSIXlt(ttext, format='%y%m%d%H%M%S'), format='%Y-%m-%dT%H:%M:%S')
    meta <- list(PhotoSens='v1.0')
    meta$file <- filename
    meta$date = timestamp        
    meta$log = list()
    meta$log = c(meta$log, list(list(action='create yaml', date=format(as.POSIXlt(Sys.time()), format='%Y-%m-%dT%H:%M:%S'))))
    dir.create(dirname(meta_file_path), showWarnings = FALSE, recursive = TRUE)
    photosens_write_yaml(meta, meta_file_path)
    cat(paste0('Created  ', meta_file_path, '\n'))
  }
}

Invoke Megadetector and Mark Images Containing People

if(!require('tools')) install.packages('tools')
if(!require('reticulate')) install.packages('reticulate')
if(!require('rjson')) install.packages('rjson')

photosens_write_yaml <- function(meta, path) {
  yaml::write_yaml(meta, file = path, precision = 11)
}

source_image_root_path <- 'archive_photo/'
source_meta_root_path  <- 'archive_meta/'

megadetector_script_path  <- 'run_detector_batch.py'  # download from MegaDetector repository
megadetector_model_path   <- 'md_v5a.0.0.pt'          # download from MegaDetector repository
megadetector_result_path  <- 'mdresult.json'

meta_files <- list.files(source_meta_root_path, pattern = '*.yaml$', recursive = TRUE, full.names = FALSE)

for(meta_file in meta_files) {
  # images and metadata files are stored in parallel
  # metadata file names: image_file_name.ext.yaml
  image_file_path <- file.path(source_meta_root_path, tools::file_path_sans_ext(meta_file))
  meta_file_path <- file.path(source_image_root_path, meta_file)

  arguments <- c(megadetector_model_path, image_file_path, megadetector_result_path, '--quiet')
  command <- paste0("import sys; ", "sys.argv = ['", megadetector_script_path, "', '", paste(arguments, collapse = "', '"), "']; ", "exec(open('", megadetector_script_path, "').read())")
  reticulate::py_run_string(command)
        
  megadetector_result_file <- rjson::fromJSON(file = megadetector_result_path)
  
  meta_data <- yaml::yaml.load_file(meta_file_path)
  meta_data$log[[2]] <- list(
    action='run MegaDetector',
    date=format(as.POSIXlt(Sys.time()), format='%Y-%m-%dT%H:%M:%S'),
    contains_person=contains_person
    )
  photosens_write_yaml(meta_data, source_meta_file_path)

  file.remove(megadetector_result_path)
}

Example Background Script

#!/bin/bash

for i in {1..1000000} # long-running but not infinite loop
do
  # safe loop exit: delete this file to stop loop after current iteration
  if [ ! -f textfile.txt ]; then
  echo "File not found: textfile.txt!"
  exit 1
  fi

  echo "Schritt $i: start processing scripts..."

  Rscript initial_yaml_generation.R
  Rscript invoke_megadetector_and_mark_people.R

  echo "Schritt $i: Sleep 15 min. "
  sleep 450  # 450 seconds = 15 minutes
done