library(camtrapR)
There are 2 function to tabulate species records after identification of species from images:
recordTable
tabulates records of all images after species-level identification andrecordTableIndividual
tabulates individuals of one species.Nevertheless, the underlying idea is the same. For each image, the date and time it was taken are read from the image’s Exif metadata using ExifTool. Species or individual ID are read from the directory structure or image metadata (see vignette “Species and Individual Identification”).
recordTable
: tabulating species recordsrecordTable
is typically run after identifying species from images. It reads species IDs from the directory structure the images are placed in or from image metadata tags.
First we define the directory containing our renamed, identified images
# find the directory with sample images contained in the package
wd_images_ID <- system.file("pictures/sample_images", package = "camtrapR")
and see how many JPG images we have (this is not necessary, but informative here).
length(list.files(wd_images_ID, pattern = "JPG", recursive = TRUE))
## [1] 68
Now we can run recordTable
. Here is a minimal example:
rec.db.species0 <- recordTable(inDir = wd_images_ID,
IDfrom = "directory")
## Warning: timeZone is not specified. Assuming UTC
## StationA : 8 images
## StationB : 23 images
## Warning: removed 6 duplicate records at station StationB
## StationC : 37 images
## Warning: removed 6 duplicate records at station StationC
head(rec.db.species0)
## Station Species DateTimeOriginal Date Time delta.time.secs
## 1 StationA PBE 2009-04-21 00:40:00 2009-04-21 00:40:00 0
## 2 StationA PBE 2009-04-22 20:19:00 2009-04-22 20:19:00 157140
## 3 StationA PBE 2009-04-22 20:21:00 2009-04-22 20:21:00 120
## 4 StationA PBE 2009-04-23 00:07:00 2009-04-23 00:07:00 13560
## 5 StationA PBE 2009-04-23 00:09:00 2009-04-23 00:09:00 120
## 6 StationA PBE 2009-05-07 17:11:00 2009-05-07 17:11:00 1270920
## delta.time.mins delta.time.hours delta.time.days
## 1 0 0.0 0.0
## 2 2619 43.6 1.8
## 3 2 0.0 0.0
## 4 226 3.8 0.2
## 5 2 0.0 0.0
## 6 21182 353.0 14.7
## Directory
## 1 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 2 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 3 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 4 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 5 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 6 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## FileName
## 1 StationA__2009-04-21__00-40-00(1).JPG
## 2 StationA__2009-04-22__20-19-00(1).JPG
## 3 StationA__2009-04-22__20-21-00(1).JPG
## 4 StationA__2009-04-23__00-07-00(1).JPG
## 5 StationA__2009-04-23__00-09-00(1).JPG
## 6 StationA__2009-05-07__17-11-00(1).JPG
Argument IDfrom
tells the function to look for species directories within the station directories and to take species IDs from these. IDfrom
must be set to “metadata” if metadata tagging was used for species identification.
By default, the function returns all records. Nevertheless, we get a data frame containing 56 records, less than the number of images in the image directory. This is because a number of images were taken at the same time (measured with 1 minute precision by these cameras) and the function removes duplicate records.
It may suffice to illustrate this with the Pig-tailed macaque images from stationB:
list.files(file.path(wd_images_ID, "StationB", "MNE"))
## [1] "StationB__2009-04-15__07-21-00(1).JPG"
## [2] "StationB__2009-04-15__07-23-00(1).JPG"
## [3] "StationB__2009-04-28__17-47-00(1).JPG"
## [4] "StationB__2009-04-28__17-47-00(2).JPG"
## [5] "StationB__2009-04-28__17-48-00(1).JPG"
## [6] "StationB__2009-04-28__17-48-00(2).JPG"
## [7] "StationB__2009-04-28__17-48-00(3).JPG"
## [8] "StationB__2009-04-28__17-49-00(1).JPG"
## [9] "StationB__2009-04-28__17-49-00(2).JPG"
## [10] "StationB__2009-04-28__17-49-00(3).JPG"
There are, amongst others, 3 images taken at 17:48:00 on the 28th of April 2009. Of these, only 1 will be returned.
Here is what the columns of the record table contain:
column | content |
---|---|
Station |
the station the image is from |
Species |
species name |
DateTimeOriginal |
Date and time of record in R-readable format |
Date |
record date |
Time |
record time of day |
delta.time.secs |
time difference between record and last (independent) record of same species at same station / camera* (in seconds) |
delta.time.mins |
time difference between record and last (independent) record of same species at same station / camera* (in minutes) |
delta.time.hours |
time difference between record and last (independent) record of same species at same station / camera* (in hours) |
delta.time.days |
time difference between record and last (independent) record of same species at same station / camera* (in days) |
Directory |
directory the image is in |
FileName |
image file name |
*see below: Independence between cameras within stations
Imagine a species that loves to hang out in front of your cameras. You will end up with hundreds of shots of the same species, maybe even the same animal. Therefore, images can be filtered using an adjustable criterion for temporal independence between subsequent records of the same species in an attempt to remove non-independent records. This is achieved via argument minDeltaTime
. It is the minimum time difference (in minutes) between two records of the same species at the same station which are to be considered independent. The default is 0, causing the function to return all records. Setting it to a higher number, e.g. 60 (i.e., 1 hour), is commonly done to thin the number of records. Note that you will not lose records of different species, even if they fall within the specified time interval from a record.
The argument deltaTimeComparedTo
further controls how independence between records is assessed. Setting it to “lastRecord” returns only records taken minDeltaTime
minutes after the last record. Setting it to “lastIndependentRecord” returns only records taken minDeltaTime
minutes after the last independent record.
Note the warning about the missing time zone. It is much advised to set it to you study area’s time zone (one of OlsonNames
). It is unlikely, but you may get into trouble if your cameras record daylight saving hours that UTC (the default) does not have. The time of day of your records will not shift when you change the time zone.
Let’s now apply an 1-hour independence criterion and define a time zone.
rec.db.species60 <- recordTable(inDir = wd_images_ID,
IDfrom = "directory",
minDeltaTime = 60,
deltaTimeComparedTo = "lastRecord",
timeZone = "Asia/Kuala_Lumpur")
## StationA : 8 images
## StationB : 23 images
## Warning: removed 6 duplicate records at station StationB
## StationC : 37 images
## Warning: removed 6 duplicate records at station StationC
nrow(rec.db.species60)
## [1] 40
Now 40 records were returned instead of 56. The missing records were taken less than 1 hour after the prior record of the same species at the same station and therefore omitted.
The issue of temporal independence between records becomes slightly more complex if more than one camera was operated at stations. That information can and should be included in the output of recordTable
(and recordTableIndividual
). Users can then decide whether temporal independence is to be assessed within stations or within cameras at each station. In the first case, argument camerasIndependent
must be set to FALSE. 2 images taken at different 2 cameras at the same station within minDeltaTime
minutes will be reported as 1 record in the record table (suitable if cameras were places in pairs). In the second case camerasIndependent
must be set to TRUE and 2 images taken at different 2 cameras at the same station within minDeltaTime
minutes will be reported as 2 record in the record table (suitable e.g., if cameras were located at some distance to one another and faced different trails).
The cameraID
argument controls where camtrapR will look for camera IDs: in the file names (after renaming using imageRename
, e.g. “renamedImages/StationA/StationA__Camera1__2015-12-31__23-59-59(1).JPG“) or in the directory structure (e.g. renamedImages/StationA/Camera1/StationA__Camera1__2015-12-31__23-59-59(1).JPG“). If missing, it will be assumed there was only 1 camera per station.
Argument exclude
can be used to ignore certain species. This is useful for omitting images in directories like “team” or “unidentified”. Here is an example:
# see what species we recorded
table(rec.db.species60$Species)
##
## EGY MNE NO_ID PBE TRA VTA
## 6 2 1 18 8 5
# remove "NO_ID" by setting argument exclude = "NO_ID"
rec.db.species60.exclude <- recordTable(inDir = wd_images_ID,
IDfrom = "directory",
minDeltaTime = 60,
deltaTimeComparedTo = "lastIndependentRecord",
timeZone = "Asia/Kuala_Lumpur",
exclude = "NO_ID")
## StationA : 8 images
## StationB : 23 images
## Warning: removed 6 duplicate records at station StationB
## StationC : 37 images
## Warning: removed 6 duplicate records at station StationC
# note that "NO_ID" is gone now
table(rec.db.species60.exclude$Species)
##
## EGY MNE PBE TRA VTA
## 6 2 18 8 5
recordTable
and recordTableIndividual
can both extract additional metadata from images (apart from date and time). For example, some camera models record ambient temperature or moon phase, which may be of interest. Metadata tags are stored in the images at the time they are taken and can be accessed and extracted if their tag names are known. Some tag names are standardised (e.g. “DateTimeOriginal”) while others are manufacturer-specific. Therefore, function exifTagNames
returns all Exif metadata it finds in a sample image. Users can then choose which to include in recordTable
and recordTableIndividual
.
wd_images_ID <- system.file("pictures/sample_images", package = "camtrapR")
exifTagNames(inDir = wd_images_ID, returnMetadata = FALSE)
## [1] "Composite:ImageSize" "Composite:ShutterSpeed"
## [3] "Composite:ThumbnailImage" "EXIF:ColorSpace"
## [5] "EXIF:ComponentsConfiguration" "EXIF:Compression"
## [7] "EXIF:CreateDate" "EXIF:DateTimeOriginal"
## [9] "EXIF:ExifImageHeight" "EXIF:ExifImageWidth"
## [11] "EXIF:ExifVersion" "EXIF:FlashpixVersion"
## [13] "EXIF:Make" "EXIF:Model"
## [15] "EXIF:ModifyDate" "EXIF:ResolutionUnit"
## [17] "EXIF:ShutterSpeedValue" "EXIF:ThumbnailLength"
## [19] "EXIF:ThumbnailOffset" "EXIF:UserComment"
## [21] "EXIF:XResolution" "EXIF:YCbCrPositioning"
## [23] "EXIF:YResolution" "ExifTool:ExifToolVersion"
## [25] "ExifTool:Warning" "File:BitsPerSample"
## [27] "File:ColorComponents" "File:Directory"
## [29] "File:EncodingProcess" "File:ExifByteOrder"
## [31] "File:FileAccessDate" "File:FileCreateDate"
## [33] "File:FileModifyDate" "File:FileName"
## [35] "File:FilePermissions" "File:FileSize"
## [37] "File:FileType" "File:ImageHeight"
## [39] "File:ImageWidth" "File:MIMEType"
## [41] "File:YCbCrSubSampling" "SourceFile"
If one has no idea what kind of data are behind these tag names, returnMetadata
can be set to TRUE to return the actual metadata instead of the tag names only.
exifTagNames(inDir = wd_images_ID, returnMetadata = TRUE)
## [1] "[ExifTool] ExifTool Version Number : 9.69"
## [2] "[ExifTool] Warning : Invalid EXIF text encoding"
## [3] "[File] File Name : StationA__2009-04-21__00-40-00(1).JPG"
## [4] "[File] Directory : C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE"
## [5] "[File] File Size : 27 kB"
## [6] "[File] File Modification Date/Time : 2016:12:19 22:58:12+01:00"
## [7] "[File] File Access Date/Time : 2016:12:19 22:58:12+01:00"
## [8] "[File] File Creation Date/Time : 2016:12:19 22:58:12+01:00"
## [9] "[File] File Permissions : rw-rw-rw-"
## [10] "[File] File Type : JPEG"
## [11] "[File] MIME Type : image/jpeg"
## [12] "[File] Exif Byte Order : Little-endian (Intel, II)"
## [13] "[File] Image Width : 100"
## [14] "[File] Image Height : 75"
## [15] "[File] Encoding Process : Baseline DCT, Huffman coding"
## [16] "[File] Bits Per Sample : 8"
## [17] "[File] Color Components : 3"
## [18] "[File] Y Cb Cr Sub Sampling : YCbCr4:2:2 (2 1)"
## [19] "[EXIF] Make : G4"
## [20] "[EXIF] Camera Model Name : CUDDEBACK"
## [21] "[EXIF] X Resolution : 72"
## [22] "[EXIF] Y Resolution : 72"
## [23] "[EXIF] Modify Date : 2009:04:21 00:40:00"
## [24] "[EXIF] Resolution Unit : inches"
## [25] "[EXIF] Y Cb Cr Positioning : Co-sited"
## [26] "[EXIF] Exif Version : 0200"
## [27] "[EXIF] Components Configuration : Y, Cb, Cr, -"
## [28] "[EXIF] Flashpix Version : 0100"
## [29] "[EXIF] Color Space : sRGB"
## [30] "[EXIF] Exif Image Width : 100"
## [31] "[EXIF] Exif Image Height : 75"
## [32] "[EXIF] Date/Time Original : 2009:04:21 00:40:00"
## [33] "[EXIF] Create Date : 2009:04:21 00:40:00"
## [34] "[EXIF] User Comment : 1 ATTEMPT G1H"
## [35] "[EXIF] Shutter Speed Value : 1"
## [36] "[EXIF] Compression : JPEG (old-style)"
## [37] "[EXIF] Thumbnail Offset : 408"
## [38] "[EXIF] Thumbnail Length : 25353"
## [39] "[Composite] Image Size : 100x75"
## [40] "[Composite] Shutter Speed : 1"
## [41] "[Composite] Thumbnail Image : (Binary data 25353 bytes, use -b option to extract)"
Note that when returnMetadata = TRUE
the tag names contain spaces whereas they don’t when returnMetadata = FALSE
. When supplying tagnames to the recordTable
functions, use the tag names without spaces (as returned when returnMetadata = FALSE
).
Please also note that exifTagNames
by default returns the metadata tag group along with the tag names (since version 0.99.6), which is helpful to unambiguously identify and extract specific metadata tags as shown in the next step.
Of the tags shown here, “DateTimeOriginal” contains the date and time that camtrapR reads out. Apart from that, there is little information of ecological interest in the example data. However, for demonstration purposes, let’s extract information about the camera model and make:
rec.db.species.metadata1 <- recordTable(inDir = wd_images_ID,
IDfrom = "directory",
timeZone = "Asia/Kuala_Lumpur",
additionalMetadataTags = c("EXIF:Model", "EXIF:Make"))
## StationA : 8 images
## StationB : 23 images
## Warning: removed 6 duplicate records at station StationB
## StationC : 37 images
## Warning: removed 6 duplicate records at station StationC
head(rec.db.species.metadata1)
## Station Species DateTimeOriginal Date Time delta.time.secs
## 1 StationA PBE 2009-04-21 00:40:00 2009-04-21 00:40:00 0
## 2 StationA PBE 2009-04-22 20:19:00 2009-04-22 20:19:00 157140
## 3 StationA PBE 2009-04-22 20:21:00 2009-04-22 20:21:00 120
## 4 StationA PBE 2009-04-23 00:07:00 2009-04-23 00:07:00 13560
## 5 StationA PBE 2009-04-23 00:09:00 2009-04-23 00:09:00 120
## 6 StationA PBE 2009-05-07 17:11:00 2009-05-07 17:11:00 1270920
## delta.time.mins delta.time.hours delta.time.days
## 1 0 0.0 0.0
## 2 2619 43.6 1.8
## 3 2 0.0 0.0
## 4 226 3.8 0.2
## 5 2 0.0 0.0
## 6 21182 353.0 14.7
## Directory
## 1 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 2 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 3 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 4 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 5 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## 6 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images/StationA/PBE
## FileName EXIF.Model EXIF.Make
## 1 StationA__2009-04-21__00-40-00(1).JPG CUDDEBACK G4
## 2 StationA__2009-04-22__20-19-00(1).JPG CUDDEBACK G4
## 3 StationA__2009-04-22__20-21-00(1).JPG CUDDEBACK G4
## 4 StationA__2009-04-23__00-07-00(1).JPG CUDDEBACK G4
## 5 StationA__2009-04-23__00-09-00(1).JPG CUDDEBACK G4
## 6 StationA__2009-05-07__17-11-00(1).JPG CUDDEBACK G4
There are 2 additional columns containing the information from the metadata we requested.
recordTableIndividual
: tabulating individuals of a speciesIndividual identification of species is a prerequiste for running (spatial) capture-recapture models. recordTableIndividual
and the subsequent spatialDetectionHistory
function prepare data for these models.
# find the directory with tagged sample images contained in the package
wd_images_individual_ID <- system.file("pictures/sample_images_tagged/LeopardCat", package = "camtrapR")
# missing space in species = "LeopardCat" is because of CRAN package policies
rec.db.pbe <- recordTableIndividual(inDir = wd_images_individual_ID,
IDfrom = "metadata",
minDeltaTime = 60,
deltaTimeComparedTo = "lastIndependentRecord",
hasStationFolders = FALSE, # images are not in station directories
metadataIDTag = "individual", # the name of the metadata tag containing individual IDs
timeZone = "Asia/Kuala_Lumpur"
)
## C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat : 26 images
## Warning: removed 3 duplicate records at station StationA, StationB,
## StationC
In addition to the metadata that were saved when the image was taken (see above), custom metadata tags assigned in image management software can also be extracted. These may contain species ID tags if species were identified using metadata tags (instead of moving images into species directories), but also individual IDs, animal counts, sex of animals recorded, etc..
head(rec.db.pbe)
## Station Species Individual DateTimeOriginal Date Time
## 1 StationA LeopardCat 1 2009-05-07 17:11:00 2009-05-07 17:11:00
## 2 StationA LeopardCat 2 2009-04-21 00:40:00 2009-04-21 00:40:00
## 3 StationA LeopardCat 2 2009-04-22 20:19:00 2009-04-22 20:19:00
## 4 StationA LeopardCat 2 2009-04-23 00:07:00 2009-04-23 00:07:00
## 5 StationB LeopardCat 1 2009-04-07 00:23:00 2009-04-07 00:23:00
## 6 StationB LeopardCat 1 2009-04-14 06:13:00 2009-04-14 06:13:00
## delta.time.secs delta.time.mins delta.time.hours delta.time.days
## 1 0 0 0.0 0.0
## 2 0 0 0.0 0.0
## 3 157140 2619 43.6 1.8
## 4 13680 228 3.8 0.2
## 5 0 0 0.0 0.0
## 6 625800 10430 173.8 7.2
## Directory
## 1 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## 2 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## 3 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## 4 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## 5 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## 6 C:/Users/Jürgen Niedballa/AppData/Local/Temp/Rtmpcnd4z5/Rinstee44ef85d42/camtrapR/pictures/sample_images_tagged/LeopardCat
## FileName metadata_Species
## 1 StationA__2009-05-07__17-11-00(1).JPG Leopard Cat
## 2 StationA__2009-04-21__00-40-00(1).JPG Leopard Cat
## 3 StationA__2009-04-22__20-19-00(1).JPG Leopard Cat
## 4 StationA__2009-04-23__00-07-00(1).JPG Leopard Cat
## 5 StationB__2009-04-07__00-23-00(1).JPG Leopard Cat
## 6 StationB__2009-04-14__06-13-00(1).JPG Leopard Cat
## metadata_individual
## 1 1
## 2 2
## 3 2
## 4 2
## 5 1
## 6 1
The camera operation matrix is a day-by-station matrix that states how many cameras were active at a station on a given day. Rows represent stations and columns days, beginning with the day the first camera was set up and ending the day the last camera was retrieved.
# first load the camera trap station table
data(camtraps)
camop_problem <- cameraOperation(CTtable = camtraps,
stationCol = "Station",
setupCol = "Setup_date",
retrievalCol = "Retrieval_date",
writecsv = FALSE,
hasProblems = TRUE,
dateFormat = "%d/%m/%Y"
)
# as a reminder, these are the dates in our station information table
camtraps[,-which(colnames(camtraps) %in% c("utm_y", "utm_x"))]
## Station Setup_date Retrieval_date Problem1_from Problem1_to
## 1 StationA 02/04/2009 14/05/2009
## 2 StationB 03/04/2009 16/05/2009
## 3 StationC 04/04/2009 17/05/2009 12/05/2009 17/05/2009
# now let's have a look at the first few columns of the camera operation matrix
camop_problem[, 1:5]
## 2009-04-02 2009-04-03 2009-04-04 2009-04-05 2009-04-06
## StationA 1 1 1 1 1
## StationB NA 1 1 1 1
## StationC NA NA 1 1 1
# and the last few
camop_problem[, (ncol(camop_problem)-6):ncol(camop_problem)]
## 2009-05-11 2009-05-12 2009-05-13 2009-05-14 2009-05-15 2009-05-16
## StationA 1 1 1 1 NA NA
## StationB 1 1 1 1 1 1
## StationC 1 0 0 0 0 0
## 2009-05-17
## StationA NA
## StationB NA
## StationC 0
If stations were not set up, values are NA. If they were set up but malfunctioning, it is 0. Operational stations get value 1.
Here is a little function for plotting the camera operation matrix. Imagine there is a typo in one of your date fields and the setup or retrieval year is wrong. You will easily be able to spot it this way.
camopPlot <- function(camOp){
which.tmp <- grep(as.Date(colnames(camOp)), pattern = "01$")
label.tmp <- format(as.Date(colnames(camOp))[which.tmp], "%Y-%m")
at.tmp <- which.tmp / ncol(camOp)
image(t(as.matrix(camOp)), xaxt = "n", yaxt = "n", col = c("red", "grey70"))
axis(1, at = at.tmp, labels = label.tmp)
axis(2, at = seq(from = 0, to = 1, length.out = nrow(camOp)), labels = rownames(camOp), las = 1)
abline(v = at.tmp, col = rgb(0,0,0, 0.2))
box()
}
And this is what we get
camopPlot(camOp = camop_problem)
The camera operation matrix can easily be saved as a csv file (by setting argument writecsv = TRUE
, check.names = FALSE
and defining outdir
). In order to load the csv into R again, it is necessary to tell R to use the station IDs (the first column) as row names:
camOp <- read.csv(file = ..., row.names = 1, check.names = FALSE)
check.names = FALSE
ensures that column names (the dates) are read back into R as they are (e.g. “2015-12-01”). Otherwise one may end up with unreadable column names (at least for camtrapR) such as “X2015.12.01”.
It is very easy to prepare input for occupancy and spatial capture-recapture (SCR) analyses in camtrapR. All one needs it a record table and the camera operation matrix. Making input for SCR analyses further requires the camera trap station table.
Occupancy models use detection/non-detection matrices in which for every station and every occasion “1”" signifies a detection of a given species and “0”" signifies non-detecion.
Here is how to obtain a detection/non-detection matrix using function detectionHistory
. Because the function builds on prior functions (recordTable
and cameraOperation
) we also show these function here to provide the context.
# create camera operation matrix
camop_no_problem <- cameraOperation(CTtable = camtraps,
stationCol = "Station",
setupCol = "Setup_date",
retrievalCol = "Retrieval_date",
hasProblems = FALSE,
dateFormat = "%d/%m/%Y"
)
# define image directory
wd_images_ID <- system.file("pictures/sample_images", package = "camtrapR")
# make record table
recordTableSample <- recordTable(inDir = wd_images_ID,
IDfrom = "directory",
minDeltaTime = 60,
deltaTimeComparedTo = "lastIndependentRecord",
timeZone = "Asia/Kuala_Lumpur"
)
## StationA : 8 images
## StationB : 23 images
## Warning: removed 6 duplicate records at station StationB
## StationC : 37 images
## Warning: removed 6 duplicate records at station StationC
# make detection history (without trapping effort)
DetHist1 <- detectionHistory(recordTable = recordTableSample,
camOp = camop_no_problem,
stationCol = "Station",
speciesCol = "Species",
recordDateTimeCol = "DateTimeOriginal",
species = "VTA",
occasionLength = 7,
day1 = "station",
includeEffort = FALSE
)
## Warning: timeZone is not specified. Assuming UTC
DetHist1
## $detection_history
## o1 o2 o3 o4 o5 o6 o7
## StationA 0 1 0 0 1 0 NA
## StationB 0 1 0 1 0 0 NA
## StationC 0 0 1 0 0 0 NA
Note the warning about the missing time zone (as in the functions recordTable
and recordTable
). Normally, it should be fine, but to be on the safe side, better set it to your study area’s time zone.
If trapping effort is thought to influence detection probability, it can be returned by setting includeEffort = TRUE
. This way the number of active trapping days per occasion and station is returned.
# make detection history (with trapping effort)
DetHist2 <- detectionHistory(recordTable = recordTableSample,
camOp = camop_no_problem,
stationCol = "Station",
speciesCol = "Species",
recordDateTimeCol = "DateTimeOriginal",
species = "VTA",
timeZone = "Asia/Kuala_Lumpur",
occasionLength = 7,
day1 = "station",
includeEffort = TRUE,
scaleEffort = FALSE
)
DetHist2[[1]] # detection history
## o1 o2 o3 o4 o5 o6 o7
## StationA 0 1 0 0 1 0 0
## StationB 0 1 0 1 0 0 0
## StationC 0 0 1 0 0 0 0
DetHist2[[2]] # effort (in days per occasion)
## o1 o2 o3 o4 o5 o6 o7
## StationA 7 7 7 7 7 7 1
## StationB 7 7 7 7 7 7 2
## StationC 7 7 7 7 7 7 2
To help with convergence of models, the effort matrix can be scaled to mean = 0 and sd = 1 by setting scaleEffort = TRUE
. If writecsv = TRUE
, the scaling parameters will also be saved in a separate csv file.
DetHist3 <- detectionHistory(recordTable = recordTableSample,
camOp = camop_no_problem,
stationCol = "Station",
speciesCol = "Species",
recordDateTimeCol = "DateTimeOriginal",
species = "VTA",
timeZone = "Asia/Kuala_Lumpur",
occasionLength = 7,
day1 = "station",
includeEffort = TRUE,
scaleEffort = TRUE
)
DetHist3[[2]] # effort (scaled)
## o1 o2 o3 o4 o5 o6
## StationA 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062
## StationB 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062
## StationC 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062 0.3966062
## o7
## StationA -2.726668
## StationB -2.206122
## StationC -2.206122
DetHist3[[3]] # scaling parameters for back-transformation
## effort.scaled.center effort.scaled.scale
## 1 6.238095 1.921061
# backtransform scaled effort like this if needed
(DetHist3[[2]] * DetHist3[[3]]$effort.scaled.scale) + DetHist3[[3]]$effort.scaled.center
## o1 o2 o3 o4 o5 o6 o7
## StationA 7 7 7 7 7 7 1
## StationB 7 7 7 7 7 7 2
## StationC 7 7 7 7 7 7 2
The following table shows the behaviour of the detectionHistory function for different occasion-level camera operation values (table head) under different combinations of the arguments includeEffort
and minActiveDaysPerOccasion
in the function detectionHistory
.
includeEffort | minActiveDaysPerOccasion | camera operation all 1 | at least one 1 | all 0 | 0 and NA | all NA | |
---|---|---|---|---|---|---|---|
TRUE | not defined | 0/1 | 0/1 | NA | NA | NA | |
TRUE | defined | 0/1 | 0/1/NA* | NA | NA | NA | |
FALSE | not defined | 0/1 | NA | NA | NA | NA | |
FALSE | defined | 0/1 | 0/1/NA* | NA | NA | NA |
*: NA if there were less active days in an occasion than minActiveDaysPerOccasion
The same applies to generation of input for spatial capture-recapture analyses using spatialDetectionHistory
as described below.
The detection history and effort matrices can easily be saved as csv files (by setting argument writecsv = TRUE
and defining outdir
). In order to load the csv into R again, it is necessary to tell R to use the station IDs as row names:
detHist <- read.csv(file = ..., row.names = 1)
effort <- read.csv(file = ..., row.names = 1)
Input for spatial capture-recapture analyses can be generated in the form of capthist
-objects as defined in the secr
package with the function spatialDetectionHistory
. Output can be in the form of counts (number of individual detections per occasion, argument, argument output = "count"
) or binary (was an individual detected during an occasion, argument output = "binary"
). note that the detector type will change accordingly: “proximity” if output = "binary"
and “count” if output = "count"
.
data(recordTableIndividualSample)
data(camtraps)
# create camera operation matrix (with problems/malfunction)
camop_problem <- cameraOperation(CTtable = camtraps,
stationCol = "Station",
setupCol = "Setup_date",
retrievalCol = "Retrieval_date",
writecsv = FALSE,
hasProblems = TRUE,
dateFormat = "%d/%m/%Y"
)
sdh <- spatialDetectionHistory(recordTableIndividual = recordTableIndividualSample,
species = "LeopardCat",
output = "binary",
camOp = camop_problem,
CTtable = camtraps,
stationCol = "Station",
speciesCol = "Species",
Xcol = "utm_x",
Ycol = "utm_y",
individualCol = "Individual",
recordDateTimeCol = "DateTimeOriginal",
recordDateTimeFormat = "%Y-%m-%d %H:%M:%S",
occasionLength = 10,
day1 = "survey",
includeEffort = TRUE,
timeZone = "Asia/Kuala_Lumpur"
)
# missing space in species = "LeopardCat" was introduced by recordTableIndividual
# (because of CRAN package policies. You can have spaces in your directory names)
summary(sdh)
## Object class capthist
## Detector type proximity
## Detector number 3
## Average spacing 2575.831 m
## x-range 523000 526000 m
## y-range 604000 607050 m
##
## Usage range by occasion
## 1 2 3 4 5
## min 8 10 10 10 0
## max 10 10 10 10 5
##
## Counts by occasion
## 1 2 3 4 5 Total
## n 2 2 3 2 1 10
## u 2 0 1 0 0 3
## f 0 1 0 2 0 3
## M(t+1) 2 2 3 3 3 3
## losses 0 0 0 0 0 0
## detections 3 4 4 3 1 15
## detectors visited 2 3 3 2 1 11
## detectors used 3 3 3 3 2 14
plot(sdh, tracks = TRUE)
## Warning in plot.capthist(sdh, tracks = TRUE): track for repeat detections
## on same occasion joins points in arbitrary sequence