Title: | Estimating Lengths and Uncertainty from Photogrammetric Imagery |
---|---|
Description: | Implementation of Bayesian models for estimating object lengths and morphological relationships between object lengths using photographic data collected from drones. The Bayesian model is described in "Bayesian approach for predicting photogrammetric uncertainty in morphometric measurements derived from drones" (Bierlich et al., 2021, <doi:10.3354/meps13814>). |
Authors: | Joshua Hewitt [aut], K.C. Bierlich [aut, cre], Enrico Pirotta [aut] |
Maintainer: | K.C. Bierlich <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.0.1 |
Built: | 2025-02-26 05:32:11 UTC |
Source: | https://github.com/mmi-codex/xcertainty |
Function that post-processes posterior samples from a sampler, such as
independent_length_sampler()
.
body_condition( data, output, length_name, width_names, width_increments, summary.burn = 0.5, height_ratios = rep(1, length(width_names)), metric = c("surface_area", "body_area_index", "body_volume", "standardized_widths") )
body_condition( data, output, length_name, width_names, width_increments, summary.burn = 0.5, height_ratios = rep(1, length(width_names)), metric = c("surface_area", "body_area_index", "body_volume", "standardized_widths") )
data |
The output from parse_observations |
output |
The return object from a sampler |
length_name |
The name of the total-length measurement in the dataset |
width_names |
Character vector with the names of the width measurements in the dataset |
width_increments |
Numeric vector indicating which perpendicular width
segment each |
summary.burn |
proportion of posterior samples to discard before computing posterior summary statistics |
height_ratios |
numeric vector used to compute |
metric |
Character vector of the body condition metrics to compute |
outputs a list with five elements:
a list containing the surface area samples and summaries for each Subject
a list containing the body area index samples and summaries for each Subject
a list containing the body volume samples and summaries for each Subject
a list containing the standardized width samples and summaries for each Subject
a list for each body condition metric containing summaries for each Subject
library(stringr) library(dplyr) # # parse data for Xcertainty # data("calibration2") data("body_condition_measurements") body_condition_measurements <- body_condition_measurements %>% select(!c(TL.10.0..Width, TL.15.0..Width, TL.5.0..Width, TL.90.0..Width, TL.95.0..Width)) # parse calibration study calibration_data = parse_observations( x = calibration2, subject_col = 'L_train', meas_col = 'RRR.pix', tlen_col = 'L_train', image_col = 'Images', barometer_col = 'Baro...Ht', laser_col = 'Laser_Alt', flen_col = 'Focal.length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'Aircraft' ) # identify the width columns in the dataset width_names = grep( pattern = 'TL\\..*', x = colnames(body_condition_measurements), value = TRUE ) # parse whale data whale_data = parse_observations( x = body_condition_measurements, #[1:5,], subject_col = 'Animal_ID', meas_col = c('TL', width_names), image_col = 'Image', barometer_col = 'BaroAlt', laser_col = 'LaserAlt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'Aircraft', alt_conversion_col = 'BaroAlt' ) # # fit a basic model or load model output # if(interactive()) { # build sampler sampler = independent_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ) ) # run sampler body_condition_measurement_estimates = sampler(niter = 1e4, thin = 100) } else { data("body_condition_measurement_estimates") } # # post-process data # # enumerate the width locations along the animal's length width_increments = as.numeric( str_extract( string = width_names, pattern = '[0-9]+' ) ) # compute body condition scores body_condition_output = body_condition( data = whale_data, output = body_condition_measurement_estimates, length_name = 'TL', width_names = width_names, width_increments = width_increments, summary.burn = .5 ) body_condition_output$summaries
library(stringr) library(dplyr) # # parse data for Xcertainty # data("calibration2") data("body_condition_measurements") body_condition_measurements <- body_condition_measurements %>% select(!c(TL.10.0..Width, TL.15.0..Width, TL.5.0..Width, TL.90.0..Width, TL.95.0..Width)) # parse calibration study calibration_data = parse_observations( x = calibration2, subject_col = 'L_train', meas_col = 'RRR.pix', tlen_col = 'L_train', image_col = 'Images', barometer_col = 'Baro...Ht', laser_col = 'Laser_Alt', flen_col = 'Focal.length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'Aircraft' ) # identify the width columns in the dataset width_names = grep( pattern = 'TL\\..*', x = colnames(body_condition_measurements), value = TRUE ) # parse whale data whale_data = parse_observations( x = body_condition_measurements, #[1:5,], subject_col = 'Animal_ID', meas_col = c('TL', width_names), image_col = 'Image', barometer_col = 'BaroAlt', laser_col = 'LaserAlt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'Aircraft', alt_conversion_col = 'BaroAlt' ) # # fit a basic model or load model output # if(interactive()) { # build sampler sampler = independent_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ) ) # run sampler body_condition_measurement_estimates = sampler(niter = 1e4, thin = 100) } else { data("body_condition_measurement_estimates") } # # post-process data # # enumerate the width locations along the animal's length width_increments = as.numeric( str_extract( string = width_names, pattern = '[0-9]+' ) ) # compute body condition scores body_condition_output = body_condition( data = whale_data, output = body_condition_measurement_estimates, length_name = 'TL', width_names = width_names, width_increments = width_increments, summary.burn = .5 ) body_condition_output$summaries
Posterior estimates for lengths and widths of a whale. See
help("body_condition")
for computation details.
body_condition_measurement_estimates
body_condition_measurement_estimates
A list with 5 elements:
Posterior samples and summaries for altimeters
Posterior samples and summaries for images
Posterior samples and summaries for pixel error component of measurement error model
Posterior samples and summaries for unknown object lengths that were estimated
data.frame
s with posterior summaries, collated from
all other list elements.
Photogrammetric measurements of humpback whales to estimate total body length and body condition.
body_condition_measurements
body_condition_measurements
A data frame with 29 rows and 28 columns:
unique ID for the individual whale
total body length measurement (m)
Width of whale (m), pre-computed from pixels using the reported laser altimeter measurement. Width is taken at a cross-section perpendicular to the whale's center line, running from the middle of the rostrum (loosely, the whale's beak/nose) to the middle of the peduncle (the point where the tail connects to the rest of the body). The cross-section is taken 10 from the animal's rostrum to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 15
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 20
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 25
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 30
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 35
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 40
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 45
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 50
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 55
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 60
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 65
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 70
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 75
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 80
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 85
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 90
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 95
to its peduncle.
Same as TL.10.0..Width
, but taken at a
cross-section that is 5
to its peduncle.
image name
the barometer altitude adjusted for the launch height of the drone
the altitude recorded by the laser (LiDAR) altimeter
focal length of the camera (mm)
image width (px)
sensor width (mm)
the unoccupied aircraft system (UAS), or drone, used in data collection
<https://doi.org/10.3389/fmars.2021.749943>
Implements Heaviside step function for use in nimble models, H(B) = 1 if B <= delta. For internal use only. Not intended to be called directly by users.
breakFun(B, delta)
breakFun(B, delta)
B |
argument to evaluate function at |
delta |
breakpoint location |
1 if B <= delta
, and 0 otherwise
breakFun(B = 1, delta = 0)
breakFun(B = 1, delta = 0)
Photogrammetric measurements of known-sized calibration objects to be used as training data.
calibration
calibration
A data frame with 657 rows and 10 columns:
the calibration object ID in training data
length measurement (px)
the true length of the calibration object (m)
image name
the barometer altitude adjusted for the launch height of the drone: Baro_raw + Launch_Ht
the altitude recorded by the laser (LiDAR) altimeter
focal length of the camera (mm)
image width (px)
sensor width (mm)
the unoccupied aircraft system (UAS), or drone, used in data collection
<https://doi.org/10.1111/gcb.17366>
Build an MCMC sampler that only uses calibration data to estimate measurement error parameters
calibration_sampler(data, priors, package_only = FALSE)
calibration_sampler(data, priors, package_only = FALSE)
data |
Photogrammetric data formatted for Xcertainty models, required to
be an object with class |
priors |
|
package_only |
|
outputs a function to run a sampler, the function arguments are:
set the number of iterations
set the number samples to discard
set the thinning rate
# load example wide-format data data("calibration") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # build sampler sampler_data = calibration_sampler( data = calibration_data, priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01) ), # set to false to return sampler function package_only = TRUE )
# load example wide-format data data("calibration") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # build sampler sampler_data = calibration_sampler( data = calibration_data, priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01) ), # set to false to return sampler function package_only = TRUE )
Photogrammetric measurements of known-sized calibration objects to be used as training data.
calibration2
calibration2
A data frame with 46 rows and 9 columns:
the true length of the calibration object (m)
length measurement (px)
image name
the barometer altitude adjusted for the launch height of the dronet
the altitude recorded by the laser (LiDAR) altimeter
focal length of the camera (mm)
image width (px)
sensor width (mm)
the unoccupied aircraft system (UAS), or drone, used in data collection
<https://doi.org/10.3389/fmars.2021.749943>
Photogrammetric measurements of known-sized calibration objects to be used as training data.
co_data
co_data
A data frame with 118 rows and 15 columns:
the unoccupied aircraft system (UAS), or drone, used in data collection
the calibration object ID in training data
the true length of the calibration object (m)
Year
image name
Date
sensor width (mm)
image width (px)
focal length of the camera (mm)
the adjusted focal length (mm) to account for internal processing that corrects for barrel distortion
raw altitude recorded by the barometer altimeter
the launch height of the drone
the barometer altitude adjusted for the launch height of the drone: Baro_raw + Launch_Ht
the altitude recorded by the laser (LiDAR) altimeter
length measurement (px)
<https://doi.org/10.1139/dsa-2023-0051>
Combine parsed observations, such as calibration and observation (whale) data into a single parsed object. This combined, single parsed object can then be used as the data input for one of the samplers.
combine_observations(...)
combine_observations(...)
... |
Parsed datasets to combine (i.e., outputs from
|
outputs a list with four elements:
a tibble containing the measurements in pixels linked with Subject, Measurement description, Image, and the Timepoint
a tibble containing the Subject, Measurement, Length, and Timepoint. NULL if no training objects were included
a tibble containing the Subject, Measurement, and Timepoint. NULL if no prediction data included
a tibble containing the Image, Barometer, Laser, FocalLength, ImageWidth, SensorWidth, and UAS
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
For internal use only. Not intended to be called directly by users.
flatten_data( data = NULL, priors, pixel_counts = data$pixel_counts, training_objects = data$training_objects, image_info = data$image_info, prediction_objects = data$prediction_objects )
flatten_data( data = NULL, priors, pixel_counts = data$pixel_counts, training_objects = data$training_objects, image_info = data$image_info, prediction_objects = data$prediction_objects )
data |
A |
priors |
|
pixel_counts |
|
training_objects |
|
image_info |
|
prediction_objects |
|
Assemble data.frame
objects into a format that can be analyzed using
numerical methods. This function is analagous to stats::model.matrix
,
which generates design matrices for models that are specified via formulas.
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
Build an MCMC sampler that uses calibration data to estimate the total length of animals. The total lengths are assumed to follow a growth curve model, so replicates across time points that include age information are required to fit the model. The length model is a von-Bertalanffy-Putter growth model, following Pirotta & Bierlich et al., (in revision).
growth_curve_sampler(data, priors, subject_info, package_only = FALSE)
growth_curve_sampler(data, priors, subject_info, package_only = FALSE)
data |
Photogrammetric data formatted for Xcertainty models, required to
be an object with class |
priors |
|
subject_info |
|
package_only |
|
outputs a function to run a sampler, the function arguments are:
set the number of iterations
set the number samples to discard
set the thinning rate
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = growth_curve_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), # priors from Agbayani et al. zero_length_age = c(mean = -5.09, sd = 0.4), growth_rate = c(mean = .18, sd = .01), # additional priors group_asymptotic_size = rbind( Female = c(mean = 12, sd = .5), Male = c(mean = 12, sd = .5) ), group_asymptotic_size_trend = rbind( Female = c(mean = 0, sd = 1), Male = c(mean = 0, sd = 1) ), subject_group_distribution = c(Female = .5, Male = .5), asymptotic_size_sd = c(min = 0, max = 10), min_calf_length = 3.5, # To model break points between 1990 and 2015 group_size_shift_start_year = c(min = 1990, max = 2015) ), subject_info = whale_info, # set to false to return sampler function package_only = TRUE )
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = growth_curve_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), # priors from Agbayani et al. zero_length_age = c(mean = -5.09, sd = 0.4), growth_rate = c(mean = .18, sd = .01), # additional priors group_asymptotic_size = rbind( Female = c(mean = 12, sd = .5), Male = c(mean = 12, sd = .5) ), group_asymptotic_size_trend = rbind( Female = c(mean = 0, sd = 1), Male = c(mean = 0, sd = 1) ), subject_group_distribution = c(Female = .5, Male = .5), asymptotic_size_sd = c(min = 0, max = 10), min_calf_length = 3.5, # To model break points between 1990 and 2015 group_size_shift_start_year = c(min = 1990, max = 2015) ), subject_info = whale_info, # set to false to return sampler function package_only = TRUE )
An example dataset of gray whale measurements from drone-based photogrammetry.
gw_data
gw_data
A tibble with 15 rows and 34 columns:
unique individual
image name
Year
Day of Year
the unoccupied aircraft system (UAS), or drone, used in data collection
focal length of the camera (mm)
the adjusted focal length (mm) to account for internal processing that corrects for barrel distortion
sensor width (mm)
image width (px)
raw altitude recorded by the barometer altimeter
the launch height of the drone
the barometer altitude adjusted for the launch height of the drone: Baro_raw + Launch_Ht
the altitude recorded by the laser (LiDAR) altimeter
the calibration object ID in training data
total body length measurement (px)
Body width measurement (px) at 5% of total length
Body width measurement (px) at 10% of total length
Body width measurement (px) at 15% of total length
Body width measurement (px) at 20% of total length
Body width measurement (px) at 25% of total length
Body width measurement (px) at 30% of total length
Body width measurement (px) at 35% of total length
Body width measurement (px) at 40% of total length
Body width measurement (px) at 45% of total length
Body width measurement (px) at 50% of total length
Body width measurement (px) at 55% of total length
Body width measurement (px) at 60% of total length
Body width measurement (px) at 65% of total length
Body width measurement (px) at 70% of total length
Body width measurement (px) at 75% of total length
Body width measurement (px) at 80% of total length
Body width measurement (px) at 85% of total length
Body width measurement (px) at 90% of total length
Body width measurement (px) at 95% of total length
<https://mmi.oregonstate.edu/gemm-lab>
Build an MCMC sampler that uses calibration data to estimate independent, unknown measurements. This model assumes all Subject/Measurement/Timepoint combinations are independent. So, this sample is well suited for data containing individuals that either have no replicate samples or have replicate samples that are independent over time, such as body condition which can increase or decrease over time, as opposed to length which should be stable or increase over time. It can also be used to estimate lengths when there are replicate measurements. However, since the model assumes all Subject/Measurement/Timepoint combinations are independent, no strength will be borrowed across temporal replication of a subject's measurements, for example.
independent_length_sampler(data, priors, package_only = FALSE)
independent_length_sampler(data, priors, package_only = FALSE)
data |
Photogrammetric data formatted for Xcertainty models, required to
be an object with class |
priors |
|
package_only |
|
outputs a function to run a sampler, the function arguments are:
set the number of iterations
set the number samples to discard
set the thinning rate
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = independent_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ), # set to false to return sampler function package_only = TRUE )
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = independent_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ), # set to false to return sampler function package_only = TRUE )
Build an MCMC sampler that uses calibration data to estimate measurements that are assumed to be non-decreasing in time. This sampler is well suited for when individuals have replicate measurements across time points but do not have age information. The model estimates changes in unique combinations of Subject/Measurement pairs over Timepoints.
nondecreasing_length_sampler(data, priors, package_only = FALSE)
nondecreasing_length_sampler(data, priors, package_only = FALSE)
data |
Photogrammetric data formatted for Xcertainty models, required to
be an object with class |
priors |
|
package_only |
|
outputs a function to run a sampler, the function arguments are:
set the number of iterations
set the number samples to discard
set the thinning rate
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = nondecreasing_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ), # set to false to return sampler function package_only = TRUE )
# load example wide-format data data("calibration") data("whales") data("whale_info") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # build sampler sampler_data = nondecreasing_length_sampler( data = combine_observations(calibration_data, whale_data), priors = list( image_altitude = c(min = 0.1, max = 130), altimeter_bias = rbind( data.frame(altimeter = 'Barometer', mean = 0, sd = 1e2), data.frame(altimeter = 'Laser', mean = 0, sd = 1e2) ), altimeter_variance = rbind( data.frame(altimeter = 'Barometer', shape = .01, rate = .01), data.frame(altimeter = 'Laser', shape = .01, rate = .01) ), altimeter_scaling = rbind( data.frame(altimeter = 'Barometer', mean = 1, sd = 1e1), data.frame(altimeter = 'Laser', mean = 1, sd = 1e1) ), pixel_variance = c(shape = .01, rate = .01), object_lengths = c(min = .01, max = 20) ), # set to false to return sampler function package_only = TRUE )
Photogrammetric data are often recorded in a wide-format data.frame
,
in which each row contains all measurement information for a single animal.
The row contains the image information (i.e., observed altitude and sensor
information) as well as all measurements for a given subject. This function
parses the wide-format data into a normalized list
of
data.frame
objects that separately describe the image and measurement
data. This function can process observations of calibration data as well as
experimental data.
parse_observations( x, subject_col, meas_col, tlen_col = NULL, image_col, barometer_col = NULL, laser_col = NULL, flen_col, iwidth_col, swidth_col, uas_col, timepoint_col = NULL, alt_conversion_col = NULL )
parse_observations( x, subject_col, meas_col, tlen_col = NULL, image_col, barometer_col = NULL, laser_col = NULL, flen_col, iwidth_col, swidth_col, uas_col, timepoint_col = NULL, alt_conversion_col = NULL )
x |
Wide-format |
subject_col |
column name in |
meas_col |
character vector of column names in |
tlen_col |
column name in |
image_col |
column name in |
barometer_col |
column name in |
laser_col |
column name in |
flen_col |
column name in |
iwidth_col |
column name in |
swidth_col |
column name in |
uas_col |
column names in |
timepoint_col |
column name in |
alt_conversion_col |
if not |
outputs a list with four elements:
a tibble containing the measurements in pixels linked with Subject, Measurement description, Image, and the Timepoint
a tibble containing the Subject, Measurement, Length, and Timepoint. NULL if no training objects were included
a tibble containing the Subject, Measurement, and Timepoint. NULL if no prediction data included
a tibble containing the Image, Barometer, Laser, FocalLength, ImageWidth, SensorWidth, and UAS
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
# load example wide-format data data("calibration") data("whales") # parse calibration study calibration_data = parse_observations( x = calibration, subject_col = 'CO.ID', meas_col = 'Lpix', tlen_col = 'CO.L', image_col = 'image', barometer_col = 'Baro_Alt', laser_col = 'Laser_Alt', flen_col = 'Focal_Length', iwidth_col = 'Iw', swidth_col = 'Sw', uas_col = 'uas' ) # parse field study whale_data = parse_observations( x = whales, subject_col = 'whale_ID', meas_col = 'TL.pix', image_col = 'Image', barometer_col = 'AltitudeBarometer', laser_col = 'AltitudeLaser', flen_col = 'FocalLength', iwidth_col = 'ImageWidth', swidth_col = 'SensorWidth', uas_col = 'UAS', timepoint_col = 'year' ) # combine parsed calibration and observation (whale) data combined_data = combine_observations(calibration_data, whale_data)
Gray whale information and metadata that pairs with 'whales' data by "Subject"
whale_info
whale_info
A data frame with 293 rows and 5 columns:
year
unique ID for individuals
sex; Male, Female (F), or NA
age in years
either 'known age' if individual was seen as a calf, or 'min age' from the date of date sighting
<https://doi.org/10.1111/gcb.17366>
Gray whale information and metadata that pairs with 'whales' data by "Subject"
whales
whales
A data frame with 826 rows and 14 columns:
unique individual
Female, Male, or NA
age in years
either 'known age' if individual was seen as a calf, or 'min age' from the date of date sighting
Year
Date
image name
the barometer altitude adjusted for the launch height of the drone
the altitude recorded by the laser (LiDAR) altimeter
focal length of the camera (mm)
image width (px)
sensor width (mm)
the unoccupied aircraft system (UAS), or drone, used in data collection
the total body length measurement in pixels
<https://doi.org/10.1111/gcb.17366>