Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ inst/doc
.ipynb
animl-py/src/animl/__pycache__/**
animl-py/src/animl/.ipynb_checkpoints/**
examples/**
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: animl
Title: A Collection of ML Tools for Conservation Research
Version: 3.1.1
Version: 3.2.0
Authors@R: c(person(given="Kyra", family="Swanson",email="tswanson@sdzwa.org", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-1496-3217")), person(given="Mathias",family="Tobler",role = "aut"))
Description: Functions required to classify subjects within camera trap field data. The package can handle both images and videos. The authors recommend a two-step approach using Microsoft's 'MegaDector' model and then a second model trained on the classes of interest.
Expand Down
3 changes: 2 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export(WorkingDirectory)
export(animl_install)
export(animl_install_instructions)
export(build_file_manifest)
export(check_python)
export(classify)
Expand All @@ -24,7 +25,7 @@ export(get_animals)
export(get_empty)
export(get_frame_as_image)
export(list_models)
export(load_animl_py)
export(load_animl)
export(load_class_list)
export(load_classifier)
export(load_data)
Expand Down
33 changes: 26 additions & 7 deletions R/classification.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
#' Save model state weights
#'
#' @param model pytorch model
#' @param out_dir directory to save model to
#' @param epoch current training epoch
#' @param stats performance metrics of current epoch
#' @param optimizer pytorch optimizer (optional)
#' @param scheduler pytorch scheduler (optional)
#'
#' @returns None
#' @export
#'
#' @examples
#' \dontrun{save_classifier(model, 'models/', 10, list(acc = 0.85))}
save_classifier <- function(model, out_dir, epoch, stats, optimizer=NULL, scheduler=NULL){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py$save_classifier(model, out_dir, epoch, reticulate::r_to_py(stats), optimizer=optimizer, scheduler=scheduler)
}

#' Load a Classifier Model and Class_list
#'
#' @param model_path path to model
Expand All @@ -13,8 +32,7 @@
#' classes <- load_class_list('sdzwa_andes_v1_classes.csv')
#' andes <- load_classifier('andes_v1.pt', nrow(classes))}
load_classifier <- function(model_path, classes, device=NULL, architecture="CTL"){
animl_py <- get("animl_py", envir = parent.env(environment()))

animl_py <- .animl_internal$animl_py
if(is.numeric(classes)){ classes = as.integer(classes)}
animl_py$load_classifier(model_path, classes, device=device, architecture=architecture)
}
Expand All @@ -35,7 +53,7 @@ load_classifier <- function(model_path, classes, device=NULL, architecture="CTL"
#' @examples
#' \dontrun{save_classifier(model, 'models/', 10, list(acc = 0.85))}
save_classifier <- function(model, out_dir, epoch, stats, optimizer=NULL, scheduler=NULL){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$save_classifier(model, out_dir, epoch, reticulate::r_to_py(stats), optimizer=optimizer, scheduler=scheduler)
}

Expand Down Expand Up @@ -78,7 +96,7 @@ classify <- function(model, detections,
batch_size=1, num_workers=1,
device=NULL, out_file=NULL){

animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$classify(model, detections,
resize_width=as.integer(resize_width),
resize_height=as.integer(resize_height),
Expand All @@ -95,13 +113,14 @@ classify <- function(model, detections,
#' @param empty manifest of md human, vehicle and empty images
#' @param predictions_raw softmaxed likelihoods from predict_species
#' @param class_list list of class labels
#' @param best whether to return one prediction per file
#'
#' @returns dataframe with prediction and confidence columns
#' @export
#'
#' @examples
#' \dontrun{animals <- single_classification(animals, empty, pred_raw, class_list)}
single_classification <- function(animals, empty, predictions_raw, class_list){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py$single_classification(animals, empty, predictions_raw, class_list)
single_classification <- function(animals, empty, predictions_raw, class_list, best=FALSE){
animl_py <- .animl_internal$animl_py
animl_py$single_classification(animals, empty, predictions_raw, class_list, best=best)
}
8 changes: 4 additions & 4 deletions R/detection.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#' \dontrun{md_py <- megadetector("/mnt/machinelearning/megaDetector/md_v5a.0.0.pt",
#' model_type='mdv5', device='cuda:0')}
load_detector <- function(model_path, model_type, device=NULL){
# first check if animl-py is loaded
animl_py <- .animl_internal$animl_py
animl_py$load_detector(model_path, model_type=model_type, device=device)
}

Expand Down Expand Up @@ -40,7 +40,8 @@ detect <- function(detector, image_file_names, resize_width, resize_height,
letterbox=TRUE, confidence_threshold=0.1, file_col='filepath',
batch_size=1, num_workers=1, device=NULL,
checkpoint_path=NULL, checkpoint_frequency=-1){
animl_py <- get("animl_py", envir = parent.env(environment()))

animl_py <- .animl_internal$animl_py
animl_py$detect(detector, image_file_names,
as.integer(resize_width), as.integer(resize_height),
letterbox=letterbox, confidence_threshold=confidence_threshold,
Expand All @@ -67,8 +68,7 @@ detect <- function(detector, image_file_names, resize_width, resize_height,
#' mdresults <- parseMD(mdres)
#' }
parse_detections <- function(results, manifest=NULL, out_file=NULL, threshold=0, file_col="filepath") {
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$parse_detections(results, manifest=manifest, out_file=out_file,
threshold=threshold, file_col=file_col)
}

24 changes: 12 additions & 12 deletions R/export.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#' Create SymLink Directories and Sort Classified Images
#'
#' @param manifest DataFrame of classified images
#' @param out_dir Destination directory for symlinks
#' @param out_dir Destination directory for species folders
#' @param out_file if provided, save the manifest to this file
#' @param label_col (str): specify 'prediction' for species or 'category' for megadetector class
#' @param label_col specify 'prediction' for species or 'category' for megadetector class
#' @param file_col Colun containing file paths
#' @param unique_name Unique image name identifier
#' @param copy Toggle to determine copy or hard link, defaults to link
Expand All @@ -18,7 +18,7 @@
export_folders <- function(manifest, out_dir, out_file=NULL,
label_col="prediction", file_col="filepath",
unique_name='uniquename', copy=FALSE) {
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
manifest <- animl_py$export_folders(manifest, out_dir, out_file,
label_col=label_col, file_col=file_col,
unique_name=unique_name, copy=copy)
Expand Down Expand Up @@ -49,7 +49,7 @@ remove_link <- function(manifest, link_col='link'){
#'
#' @param manifest dataframe containing file data and predictions
#' @param export_dir directory to sort files into
#' @param unique_name column name indicating a unique file name for each row
#' @param unique_name column containing unique file names
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason there is a default value for unique_name since this is a required parameters?

#'
#' @return dataframe with new "Species" column that contains the verified species
#' @export
Expand Down Expand Up @@ -87,7 +87,7 @@ update_labels_from_folders <- function(manifest, export_dir, unique_name='unique
#' @examples
#' \dontrun{export_megadetector(manifest, output_file= 'results.json', detector='MDv6')}
export_coco <- function(manifest, class_list, out_file, info=NULL, licenses=NULL){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$export_coco(manifest, class_list, out_file, info=info, licenses=licenses)
}

Expand All @@ -114,7 +114,7 @@ export_coco <- function(manifest, class_list, out_file, info=NULL, licenses=NULL
export_camtrapR <- function(manifest, out_dir, out_file=NULL, label_col='prediction',
file_col="filepath", station_col='station',
unique_name='uniquename', copy=FALSE){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$export_camtrapR(manifest, out_dir, out_file=out_file, label_col=label_col,
file_col=file_col, station_col=station_col,
unique_name=unique_name, copy=copy)
Expand All @@ -123,18 +123,18 @@ export_camtrapR <- function(manifest, out_dir, out_file=NULL, label_col='predict

#' Converts the Manifests to a csv file that contains columns needed for TimeLapse conversion in later step
#'
#' @param results a DataFrame that has entries of anuimal classification
#' @param image_dir location of root directory where all images are stored (can contain subdirectories)
#' @param manifest a DataFrame that has entries of anuimal classification
#' @param out_dir location of root directory where all images are stored (can contain subdirectories)
#' @param only_animal A bool that confirms whether we want only animal detctions or all
#'
#' @returns animals.csv, non-anim.csv, csv_loc
#' @export
#'
#' @examples
#' \dontrun{export_timelapse(animals, empty, '/path/to/images/')}
export_timelapse <- function(results, image_dir, only_animal=TRUE){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py$export_timelapse(results, image_dir, only_animal=only_animal)
export_timelapse <- function(manifest, out_dir, only_animal=TRUE){
animl_py <- .animl_internal$animl_py
animl_py$export_timelapse(manifest, out_dir, only_animal=only_animal)
}


Expand All @@ -152,7 +152,7 @@ export_timelapse <- function(results, image_dir, only_animal=TRUE){
#' \dontrun{export_megadetector(manifest, output_file= 'results.json', detector='MDv6')}
export_megadetector <- function(manifest, out_file=NULL,
detector='MegaDetector v5a', prompt=TRUE){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$export_megadetector(manifest, out_file=out_file,
detector=detector, prompt=prompt)
}
Expand Down
10 changes: 5 additions & 5 deletions R/file_management.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#' }
build_file_manifest <- function(image_dir, exif=TRUE, out_file=NULL,
offset=0, recursive=TRUE) {
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
manifest <- animl_py$build_file_manifest(image_dir, exif=exif, out_file=out_file, offset=offset, recursive=recursive)
return(manifest)
}
Expand Down Expand Up @@ -145,7 +145,7 @@ check_file <- function(file, output_type) {
#' save_json(mdresults, 'mdraw.json')
#' }
save_json <- function(data, out_file, prompt=TRUE){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$save_json(data, out_file, prompt=prompt)
}

Expand All @@ -162,7 +162,7 @@ save_json <- function(data, out_file, prompt=TRUE){
#' mdraw <- load_json('mdraw.json')
#' }
load_json <- function(file){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$load_json(file)
}

Expand All @@ -181,7 +181,7 @@ load_json <- function(file){
#' download_model("https://models.com/path/to/model.pt", out_dir='models')
#' }
download_model <- function(model_url, out_dir='models'){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$download_model(model_url, out_dir = out_dir)
}

Expand All @@ -196,6 +196,6 @@ download_model <- function(model_url, out_dir='models'){
#' download_model("https://models.com/path/to/model.pt", out_dir='models')
#' }
list_models <- function(){
animl_py <- get("animl_py", envir = parent.env(environment()))
animl_py <- .animl_internal$animl_py
animl_py$list_models()
}
Loading