| Title: | Preprocessing Trap Camera Data for Machine Learning Models |
| Version: | 0.3.0 |
| Description: | Provides tools for preprocessing camera trap image data to prepare it for training machine learning models. It automates tasks such as extracting EXIF metadata, processing and analyzing image attributes, selecting relevant images (e.g., daytime photos), sampling subsets, and managing file organization. These features streamline the workflow for ecological research and wildlife monitoring projects. Additionally, the package includes tools for generating exploratory visualizations and creating annotation datasets. |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| Imports: | dplyr, tidyr, lubridate, stringr, ggplot2, readr, fs, exifr, rlang, tibble, progressr |
| Suggests: | future, future.apply, knitr, rmarkdown, testthat |
| Depends: | R (≥ 4.1.0) |
| VignetteBuilder: | knitr |
| NeedsCompilation: | no |
| Packaged: | 2026-10-02 00:31:32 UTC; artu |
| Author: | Edlin Guerra-Castro
|
| Maintainer: | Arturo Sanchez-Porras <sp.arturo@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-14 15:32:11 UTC |
Copy files into batch folders using fs
Description
Copies files listed in a data frame into destination subfolders of fixed size. This is useful when a large image collection must be reorganized into evenly sized groups (for example, 250 files per folder) while preserving a record of the operation.
Usage
copy_in_batches(
df,
output_dir,
batch_size = 250L,
folder_prefix = "batch_",
rename_with_id = TRUE,
overwrite = FALSE,
dry_run = FALSE,
verbose = TRUE
)
Arguments
df |
A |
output_dir |
Character scalar. Root directory where batch folders will be created. |
batch_size |
Integer scalar. Number of files per destination folder.
Default is |
folder_prefix |
Character scalar. Prefix used to name batch folders.
Default is |
rename_with_id |
Logical. If |
overwrite |
Logical. If |
dry_run |
Logical. If |
verbose |
Logical. If |
Details
Files are assigned to folders according to their row order in df.
Expected minimum input columns (contract): df must include id and
path.
Produced columns: returns one row per valid input record with id,
path, source_exists, batch_id, batch_folder_name, dest_file_name,
dest_path, copied, and status.
I/O side-effects: creates output_dir and batch subfolders when
dry_run = FALSE; copies files into those subfolders unless dry_run = TRUE.
The function creates one folder per batch using zero-padded sequential numbering, for example:
-
batch_001 -
batch_002 -
batch_003
Destination file names are generated from the source file name. When
rename_with_id = TRUE, the output name becomes:
"{id}_{original_filename}"
If duplicates remain within a batch, they are disambiguated with
base::make.unique().
The function returns a data frame describing the outcome for each row, including whether the source existed, the assigned batch, the destination path, and the copy status.
Value
A data.frame with one row per valid input file and the following columns:
- id
Identifier from the input data frame.
- path
Original source path.
- source_exists
Logical; whether the source file existed.
- batch_id
Integer batch number assigned to the file.
- batch_folder_name
Name of the destination batch folder.
- dest_file_name
Destination file name.
- dest_path
Full destination path.
- copied
Logical indicating whether the copy succeeded.
NAindry_runmode.- status
Character status label such as
"copied","source_not_found","destination_exists_not_overwritten","copy_failed", or"dry_run".
See Also
rename_images(), process_metadata(), generate_plot(),
process_training_images()
Examples
# Create temporary source and output directories
src_dir <- tempfile("cam2model_batch_src_")
out_dir <- tempfile("cam2model_batch_out_")
dir.create(src_dir, recursive = TRUE, showWarnings = FALSE)
dir.create(out_dir, recursive = TRUE, showWarnings = FALSE)
file1 <- file.path(src_dir, "img1.jpg")
file2 <- file.path(src_dir, "img2.jpg")
file3 <- file.path(src_dir, "img3.jpg")
writeBin(charToRaw("a"), file1)
writeBin(charToRaw("b"), file2)
writeBin(charToRaw("c"), file3)
df <- data.frame(
id = c("A01", "A02", "A03"),
path = c(file1, file2, file3),
stringsAsFactors = FALSE
)
# Dry run: inspect the planned organization without copying
report_dry <- copy_in_batches(
df = df,
output_dir = out_dir,
batch_size = 2,
dry_run = TRUE,
verbose = FALSE
)
report_dry[, c("id", "batch_folder_name", "dest_file_name", "status")]
# Actual copy
report <- copy_in_batches(
df = df,
output_dir = out_dir,
batch_size = 2,
dry_run = FALSE,
verbose = FALSE
)
report[, c("id", "dest_path", "status")]
Generate Custom Plots from Metadata
Description
Generates ggplot2 visualizations for processed camera-trap metadata,
with flexible x/y mappings, optional color/faceting, and optional filtering.
Usage
generate_plot(
processed_metadata,
x,
y,
color = NULL,
facets = NULL,
filter_expr = NULL,
angle = 0
)
Arguments
processed_metadata |
A data frame containing processed metadata. |
x |
Bare column name to use for the x-axis. |
y |
Bare column name to use for the y-axis. |
color |
Bare column name (optional) to map to point/line color. |
facets |
Bare column name (optional) used in |
filter_expr |
Expression (optional) used to filter the metadata before plotting. |
angle |
Numeric. Angle for x-axis labels. Default is |
Details
Expected minimum input columns (contract): the columns referenced in
x and y, and optionally those used in color, facets, and
filter_expr.
Produced columns/artifacts: none (no data is modified on disk). The
function returns a ggplot object combining geom_line() and geom_point().
I/O side-effects: none.
Value
A ggplot object.
See Also
rename_images(), process_metadata(), process_training_images(),
copy_in_batches()
Examples
demo_metadata <- data.frame(
Image_dttm = as.POSIXct("2024-08-01 00:00:00", tz = "UTC") + 0:5 * 3600,
bLuma = c(100, 120, 140, 130, 150, 160),
Camera = rep(c("C1", "C2"), each = 3),
stringsAsFactors = FALSE
)
p <- generate_plot(
processed_metadata = demo_metadata,
x = Image_dttm,
y = bLuma,
color = Camera,
facets = Camera
)
p
Process Camera Trap Metadata
Description
Extracts EXIF metadata from images in a directory, processes the
UserComment column, and saves the resulting metadata to a CSV file.
Usage
process_metadata(output_dir, output_file, UserComment = FALSE)
Arguments
output_dir |
Character. Path to the main directory containing camera folders with renamed images. |
output_file |
Character. Relative file path (from |
UserComment |
Logical. Default |
Details
Expected minimum input columns (internal contract): none. This function
reads EXIF tags directly from image files under output_dir and appends a
Camera column derived from each first-level folder name.
Produced columns: varies by EXIF availability. Output always includes
available EXIF fields plus Camera; when UserComment = TRUE and parsing is
successful, it may also include Image_dttm, File_date, File_hms,
File_hour, File_minute, and parsed fields such as temp/bLuma.
I/O side-effects: writes one CSV to file.path(output_dir, output_file).
The function does not create missing parent directories for output_file.
Value
A tibble with processed metadata. Typical contract columns used by
downstream functions include Directory and FileName (required by
process_training_images()).
See Also
rename_images(), generate_plot(), process_training_images(),
copy_in_batches()
Examples
## Not run:
# Requires real image files with EXIF metadata.
renamed_dir <- tempfile("cam2model_renamed_")
dir.create(renamed_dir, recursive = TRUE)
dir.create(file.path(renamed_dir, "camera_A"), recursive = TRUE)
# Copy real camera-trap images into `renamed_dir/camera_A` before running.
meta <- process_metadata(
output_dir = renamed_dir,
output_file = "metadata.csv",
UserComment = FALSE
)
file.exists(file.path(renamed_dir, "metadata.csv"))
head(meta)
## End(Not run)
Process and Select Images for Training
Description
Filters metadata according to one or more rules, samples a per-directory proportion of images, optionally copies sampled images to a destination directory, and generates CSV files for bookkeeping and annotation.
Usage
process_training_images(
metadata_file,
dest_dir,
output_sample_file,
output_annotation_file,
sample_proportion = 0.5,
filters = NULL,
min_per_dir = 1,
max_per_dir = Inf,
copy_images = FALSE,
parallel = FALSE,
workers = NULL,
show_progress = TRUE
)
Arguments
metadata_file |
Character. Path to the CSV file containing metadata. |
dest_dir |
Character. Path to the directory where outputs are written. |
output_sample_file |
Character. Name of the CSV file storing the sampled image list. |
output_annotation_file |
Character. Name of the CSV file storing the annotation template. |
sample_proportion |
Numeric in |
filters |
A list of filtering rules. Each rule must be a list with:
If |
min_per_dir |
Integer. Minimum number of images to sample per directory. |
max_per_dir |
Integer. Maximum number of images to sample per directory. |
copy_images |
Logical. If |
parallel |
Logical. If |
workers |
Integer or NULL. Number of workers for parallel copying. |
show_progress |
Logical. If |
Details
Expected minimum input columns (contract): Directory and FileName
must be present in metadata_file.
Produced columns: returns sampled rows with at least Directory,
FileName, optional File_date/File_hour (if present in input), and
file_path; adds dest_file and copied when copy_images = TRUE.
I/O side-effects:
Creates
dest_dirif it does not exist.Writes sampled CSV to
file.path(dest_dir, output_sample_file).Writes annotation template CSV to
file.path(dest_dir, output_annotation_file).Optionally copies sampled files into
dest_dirwhencopy_images = TRUE.
Value
A tibble with sampled images and file paths used for training.
See Also
rename_images(), process_metadata(), generate_plot(),
copy_in_batches()
Examples
src_dir <- tempfile("cam2model_train_src_")
dest_dir <- tempfile("cam2model_train_out_")
dir.create(src_dir, recursive = TRUE)
# Create minimal files that can be referenced from metadata
f1 <- file.path(src_dir, "img1.jpg")
f2 <- file.path(src_dir, "img2.jpg")
writeBin(charToRaw("a"), f1)
writeBin(charToRaw("b"), f2)
metadata_tbl <- data.frame(
Directory = c(src_dir, src_dir),
FileName = c("img1.jpg", "img2.jpg"),
File_hour = c(10, 14),
stringsAsFactors = FALSE
)
metadata_csv <- tempfile("cam2model_metadata_", fileext = ".csv")
readr::write_csv(metadata_tbl, metadata_csv)
sampled <- process_training_images(
metadata_file = metadata_csv,
dest_dir = dest_dir,
output_sample_file = "sampled_images.csv",
output_annotation_file = "annotation_data.csv",
sample_proportion = 1,
copy_images = FALSE,
show_progress = FALSE,
parallel = FALSE
)
sampled
file.exists(file.path(dest_dir, "sampled_images.csv"))
file.exists(file.path(dest_dir, "annotation_data.csv"))
Rename and flatten camera trap images
Description
This wrapper function builds a renaming plan and immediately executes it, allowing the user to flatten and rename all images from a sampling-site directory in a single call.
Usage
rename_images(
input_dir,
output_dir,
site_name = NULL,
recursive = TRUE,
extensions = c("jpg", "jpeg", "png", "tif", "tiff"),
keep_relative_path = TRUE,
date_fields = c("DateTimeOriginal", "FileModifyDate"),
parallel = FALSE,
workers = NULL,
overwrite = FALSE,
return_plan = FALSE
)
Arguments
input_dir |
Character. Path to the root directory of a sampling site. |
output_dir |
Character. Path to the root output directory. |
site_name |
Character or NULL. Name of the sampling site. If |
recursive |
Logical. Should files be searched recursively? Default |
extensions |
Character vector. Allowed image extensions. |
keep_relative_path |
Logical. If |
date_fields |
Character vector. EXIF date fields to try in order. |
parallel |
Logical. Should the renaming plan be built in parallel?
Default |
workers |
Integer or NULL. Number of workers when |
overwrite |
Logical. Should existing files be overwritten? Default |
return_plan |
Logical. If |
Details
Expected minimum input columns (internal contract): none. The function
reads image files directly from input_dir and builds metadata internally.
Produced columns:
If
return_plan = FALSE, returns the execution table with columns from the renaming plan pluscopied.If
return_plan = TRUE, returns a list with:-
plan: planning table that includesoriginal_path,new_name, andnew_path. -
result: the same rows pluscopied.
-
I/O side-effects: creates <output_dir>/<site_name> when needed and
copies files to that folder using standardized names.
Value
A tibble with copy results, or a list containing both the plan and the execution result.
See Also
process_metadata(), generate_plot(), process_training_images(),
copy_in_batches()
Examples
## Not run:
# Requires real image files on disk.
raw_dir <- tempfile("cam2model_raw_")
out_dir <- tempfile("cam2model_out_")
dir.create(raw_dir, recursive = TRUE)
dir.create(out_dir, recursive = TRUE)
# Copy real camera-trap images into `raw_dir` before running.
result <- rename_images(
input_dir = raw_dir,
output_dir = out_dir,
site_name = "site_demo",
overwrite = FALSE
)
head(result)
## End(Not run)