Generates a record table from camera trap images or videos. Images/videos must be sorted into station directories at least. The function can read species identification from a directory structure (Station/Species or Station/Camera/Species) or from image metadata tags.

recordTable(
  inDir,
  IDfrom,
  cameraID,
  camerasIndependent,
  exclude,
  minDeltaTime = 0,
  deltaTimeComparedTo,
  timeZone,
  stationCol,
  writecsv = FALSE,
  outDir,
  metadataHierarchyDelimitor = "|",
  metadataSpeciesTag,
  additionalMetadataTags,
  removeDuplicateRecords = TRUE,
  returnFileNamesMissingTags = FALSE,
  eventSummaryColumn,
  eventSummaryFunction,
  video
)

Arguments

inDir

character. Directory containing station directories. It must either contain images in species subdirectories (e.g. inDir/StationA/SpeciesA) or images with species metadata tags (without species directories, e.g. inDir/StationA).

IDfrom

character. Read species ID from image metadata ("metadata") of from species directory names ("directory")?

cameraID

character. Where should the function look for camera IDs: 'filename', 'directory'. 'filename' requires images renamed with imageRename. 'directory' requires a camera subdirectory within station directories (station/camera/species). Can be missing.

camerasIndependent

logical. If TRUE, species records are considered to be independent between cameras at a station.

exclude

character. Vector of species names to be excluded from the record table

minDeltaTime

integer. Time difference between records of the same species at the same station to be considered independent (in minutes)

deltaTimeComparedTo

character. For two records to be considered independent, must the second one be at least minDeltaTime minutes after the last independent record of the same species ("lastIndependentRecord"), or minDeltaTime minutes after the last record ("lastRecord")?

timeZone

character. Must be a value returned by OlsonNames

stationCol

character. Name of the camera trap station column. Assuming "Station" if undefined.

writecsv

logical. Should the record table be saved as a .csv?

outDir

character. Directory to save csv to. If NULL and writecsv = TRUE, recordTable will be written to inDir.

metadataHierarchyDelimitor

character. The character delimiting hierarchy levels in image metadata tags in field "HierarchicalSubject". Either "|" or ":".

metadataSpeciesTag

character. In custom image metadata, the species ID tag name.

additionalMetadataTags

character. Additional camera model-specific metadata tags to be extracted. (If possible specify tag groups as returned by exifTagNames)

removeDuplicateRecords

logical. If there are several records of the same species at the same station (also same camera if cameraID is defined) at exactly the same time, show only one?

returnFileNamesMissingTags

logical. If species are assigned with metadata and images are not tagged, return a few file names of these images as a message?

eventSummaryColumn

character. A column in the record table (e.g. from a metadata tag) by to summarise non-independent records (those within minDeltaTime of a given record) with a user-defined function (eventSummaryFunction)

eventSummaryFunction

character. The function by which to summarise eventSummaryColumn of non-independent records, e.g. "sum", "max" (optional)

video

list. Contains information on how to handle video data (optional). See details.

Value

A data frame containing species records and additional information about stations, date, time and (optionally) further metadata.

Details

The function can handle a number of different ways of storing images, and supports species identification by moving images into species directories as well as metadata tagging. In every case, images need to be stored into station directories. If images are identified by moving them into species directories, a camera directory is optional: "Station/Species/XY.JPG" or "Station/Camera/Species/XY.JPG". Likewise, if images are identified using metadata tagging, a camera directory can be used optionally: "Station/XY.JPG" or "Station/Camera/XY.JPG".

If images are identified by metadata tagging, metadataSpeciesTag specifies the metadata tag group name that contains species identification tags. metadataHierarchyDelimitor is "|" for images tagged in DigiKam and images tagged in Adobe Bridge / Lightroom with the default settings. It is only necessary to change it if the default was changed in these programs.

minDeltaTime is a criterion for temporal independence of species recorded at the same station. Setting it to 0 will make the function return all records. Setting it to a higher value will remove records that were taken less than minDeltaTime minutes after the last record (deltaTimeComparedTo = "lastRecord") or the last independent record (deltaTimeComparedTo = "lastIndependentRecord").

removeDuplicateRecords determines whether duplicate records (identical station, species, date/time, (and camera if applicable)) are all returned (FALSE) or collapsed into a single unique record (TRUE).

camerasIndependent defines if the cameras at a station are to be considered independent. If TRUE, records of the same species taken by different cameras are considered independent (e.g. if they face different trails). Use FALSE if both cameras face each other and possibly TRUE ).

exclude can be used to exclude "species" directories containing irrelevant images (e.g. "team", "blank", "unidentified"). stationCol can be set to match the station column name in the camera trap station table (see camtraps).

Many digital images contain Exif metadata tags such as "AmbientTemperature" or "MoonPhase" that can be extracted if specified in metadataTags. Because these are manufacturer-specific and not standardized, function exifTagNames provides a vector of all available tag names. Multiple names can be specified as a character vector as: c(Tag1, Tag2, ...). The metadata tags thus extracted may be used as covariates in modelling species distributions.

eventSummaryColumn and eventSummaryFunction can be used to extract summary statistics for independent sampling events. For example, you assigned a "count" tag to your images, indicating the number of individuals in a picture. In a sequence of pictures taken within 1 minute, most pictures show one individual, but one image shows two individuals. You tagged the images accordingly (count = 1 or count = 2) and run recordTable. Set eventSummaryColumn = "count" and eventSummaryFunction = "max" to obtain the maximum number of count in all images within minDeltaTime minutes of a given record. The results is in a new column, in this example count_max. You can also calculate several statistics at the same time, by supplying vectors of values, e.g. eventSummaryColumn = c("count", "count", "camera") and eventSummaryFunction = c("min", "max", "unique") to get minimum and maximum count and all unique camera IDs for that event. Note that eventSummaryColumn and eventSummaryFunction must be of same length.

Argument video is a named list with 2 or 4 items. 2 items (file_formats, dateTimeTag) are always required, and are sufficent if IDfrom = "directory". In that case, no digiKam tags will be returned. To return digiKam tags, two additional items are required (db_directory, db_filename). This is essential when using IDfrom = "metadata". When using IDfrom = "directory", it is optional, but allows to extract metadata tags assigned to videos in digiKam. This workaround is necessary because digiKam tags are not written into video metadata, but are only saved in the digiKam database. So in contrast to JPG images, they can not be extracted with ExifTool. It also requires that inDir is in your digiKam database.

The items of argument video are:

file_formatsThe video formats to extract (include "jpg" if you want .JPG image metadata)
dateTimeTagthe metadata tag to extract date/time from (use exifTagNames to find out which tag is suitable)
db_directoryThe directory containing digiKam database (optional if IDfrom = "directory")
db_filenameThe digiKam database file in db_directory (optional if IDfrom = "directory")

See the examples below for for how to specify the argument video.

Note

The results of a number of other function will depend on the output of this function (namely on the arguments exclude for excluding species and minDeltaTime/ deltaTimeComparedTo for temporal independence):

detectionMaps
detectionHistory
activityHistogram
activityDensity
activityRadial
activityOverlap
activityHistogram
surveyReport

Warning

Custom image metadata must be organised hierarchically (tag group - tag; e.g. "Species" - "Leopard Cat"). Detailed information on how to set up and use metadata tags can be found in vignette 2: Species and Individual Identification.

Custom image metadata tags must be written to the images. The function cannot read tags from .xmp sidecar files. Make sure you set the preferences accordingly. In DigiKam, go to Settings/Configure digiKam/Metadata. There, make sure "Write to sidecar files" is unchecked.

Please note the section about defining argument timeZone in the vignette on data extraction (accessible via vignette("DataExtraction") or online (https://cran.r-project.org/package=camtrapR/vignettes/camtrapr3.pdf)).

References

Phil Harvey's ExifTool https://exiftool.org/

Author

Juergen Niedballa

Examples




if (FALSE)    # the examples take too long to pass CRAN tests


# set directory with camera trap images in station directories
wd_images_ID_species <- system.file("pictures/sample_images_species_dir", 
                                    package = "camtrapR")

if (Sys.which("exiftool") != ""){        # only run these examples if ExifTool is available


rec_table1 <- recordTable(inDir               = wd_images_ID_species,
                       IDfrom                 = "directory",
                       minDeltaTime           = 60,
                       deltaTimeComparedTo    = "lastRecord",
                       writecsv               = FALSE,
                       additionalMetadataTags = c("EXIF:Model", "EXIF:Make")
)
# note argument additionalMetadataTags: it contains tag names as returned by function exifTagNames

rec_table2 <- recordTable(inDir               = wd_images_ID_species,
                       IDfrom                 = "directory",
                       minDeltaTime           = 60,
                       deltaTimeComparedTo    = "lastRecord",
                       exclude                = "UNID",
                       writecsv               = FALSE,
                       timeZone               = "Asia/Kuala_Lumpur",
                       additionalMetadataTags = c("EXIF:Model", "EXIF:Make", "NonExistingTag"),
                       eventSummaryColumn     = "EXIF:Make",
                       eventSummaryFunction   = "unique"
                       )
                       
# note the warning that the last tag in "additionalMetadataTags" ("NonExistingTag") was not found


any(rec_table1$Species == "UNID")    # TRUE
any(rec_table2$Species == "UNID")    # FALSE


# here's how the removeDuplicateRecords argument works

rec_table3a <- recordTable(inDir              = wd_images_ID_species,
                       IDfrom                 = "directory",
                       minDeltaTime           = 0,
                       exclude                = "UNID",
                       timeZone               = "Asia/Kuala_Lumpur",
                       removeDuplicateRecords = FALSE
)

rec_table3b <- recordTable(inDir              = wd_images_ID_species,
                       IDfrom                 = "directory",
                       minDeltaTime           = 0,
                       exclude                = "UNID",
                       timeZone               = "Asia/Kuala_Lumpur",
                       removeDuplicateRecords = TRUE
)


anyDuplicated(rec_table3a[, c("Station", "Species", "DateTimeOriginal")])   # got duplicates
anyDuplicated(rec_table3b[, c("Station", "Species", "DateTimeOriginal")])   # no duplicates

# after removing duplicates, both are identical:
whichAreDuplicated <- which(duplicated(rec_table3a[,c("Station", "Species", "DateTimeOriginal")]))
all(rec_table3a[-whichAreDuplicated,] == rec_table3b)


### extracting species IDs from metadata

wd_images_ID_species_tagged <- system.file("pictures/sample_images_species_tag", 
                                           package = "camtrapR")

rec_table4 <- recordTable(inDir               = wd_images_ID_species_tagged,
                       IDfrom                 = "metadata",
                       metadataSpeciesTag     = "Species",
                       exclude                = "unidentified")


###  Including videos
# sample videos are not included in package

# with videos, IDfrom = "directory", not extracting digiKam metadata

rec_table4 <- recordTable(inDir  = wd_images_ID_species,
                          IDfrom = "directory",
                          video  = list(file_formats = c("jpg", "mp4"),
                                        dateTimeTag  = "QuickTime:CreateDate")
)

# with videos, IDfrom = "metadata", extracting digiKam metadata

rec_table5 <- recordTable(inDir  = wd_images_ID_species,
                          IDfrom = "metadata",
                          metadataSpeciesTag = "Species",
                          video  = list(file_formats = c("jpg", "mp4", "avi", "mov"),
                                        dateTimeTag  = "QuickTime:CreateDate",
                                        db_directory = "C:/Users/YourName/Pictures",
                                        db_filename = "digikam4.db")
)

} else {  
# show function output if ExifTool is not available
message("ExifTool is not available. Cannot test function. Loading recordTableSample instead")
data(recordTableSample)
}
#> timeZone is not specified. Assuming UTC
#> Error in eval(expr, envir, enclos): object 'wd_images_ID_species' not found