본문으로 건너뛰기
튜토리얼27분 분량

MegaDetector 결과를 검토하고 GBIF에 게시하기

카메라 트랩 이미지에 MegaDetector를 실행하고, Potato에서 자원봉사자 두 명과 전문가가 종 이름을 붙이게 한 뒤, 검증을 통과하는 Camtrap DP 패키지를 내보냅니다.

Potato Team

MegaDetector(Beery et al., 2019)를 실행하는 카메라 트랩 프로젝트는 이 튜토리얼을 따라 Potato 2.12.1에서 자원봉사자 두 명이 모든 시퀀스의 종 이름을 붙이게 하고, 불일치는 전문가에게 보내고, GBIF용 Camtrap DP 패키지를 내보낼 수 있습니다. MegaDetector는 카메라 트랩 이미지에서 동물, 사람, 차량마다 상자를 그리는 오픈 소스 모델이며, MegaDetector의 README는 이 모델이 "only finds animals, it doesn't identify them to species level"이라고 밝힙니다. Camtrap DP는 카메라 트랩 데이터를 위한 TDWG 데이터 교환 형식으로, 배치(deployment), 미디어, 관찰의 표로 이루어져 있으며, GBIF는 Camtrap DP 패키지를 출현 기록으로 처리합니다. 실제 사례는 콜롬비아의 카메라 두 대에서 얻은 공개 이미지 99장에 MegaDetector를 실행하고 Camtrap DP 검증기를 통과하는 패키지로 끝납니다. 카메라 트랩이 모든 가져오기 및 내보내기 옵션을 설명합니다.

이 안내는 Potato 2.12.1에서 실행했고, GBIF 절의 준비 스크립트가 2.12.1의 내보내기를 읽기 때문에 설치 명령도 2.12.1로 고정합니다. Potato 2.13.1은 내보내기와 이미지 검토를 바꾸며, 아래 절들은 각 변경이 적용되는 곳에서 그 내용을 설명합니다.

이미지와 정답 키

이미지는 LILA BC의 Orinoquía Camera Traps에서 가져왔으며, 콜롬비아 메타(Meta)주의 El Rey Zamuro와 Las Unamas 보호구역의 카메라에서 얻은 104,782장의 이미지로, Community Data License Agreement 허용형(CDLA-Permissive-1.0)으로 공개되었습니다. LILA는 데이터셋 사용자에게 카메라 트랩 데이터를 위한 AI 플랫폼의 평가인 Vélez et al. (2023)을 인용하라고 요청합니다. 이 평가는 빈 이미지와 동물 이미지를 분리하는 데서 MegaDetector의 정밀도와 재현율이 높고, 다른 세 플랫폼의 종 분류 재현율은 대체로 낮거나 중간 수준임을 발견했습니다. 테스트 실행은 카메라 M04와 N29에서 세 장짜리 시퀀스 33개, 총 99장을 가져왔으며, 동물 시퀀스 23개와 빈 시퀀스 10개였습니다. 데이터셋의 모든 이미지에는 전문가의 종 라벨이 있고, 테스트 실행에서 이 라벨이 검토자의 정답 키 역할을 했습니다.

LILA는 각 이미지를 https://storage.googleapis.com/public-datasets-lila/orinoquia-camera-traps/public/ 뒤에 N29/105EK113/04110961.JPG 같은 이미지 경로를 붙여 제공합니다. 이미지를 traps/라는 폴더에 넣고 경로를 유지하세요. 그러면 각 경로의 첫 번째 폴더가 카메라를 나타냅니다.

MegaDetector 실행

아래 명령은 MegaDetector를 설치하고, 첫 실행 때 MegaDetector 5a(281MB)를 내려받고, 폴더에 대해 결과 파일 하나를 씁니다.

bash
pip install megadetector
python -m megadetector.detection.run_detector_batch MDV5A traps/ md_output.json \
    --recursive --output_relative_filenames --include_image_timestamp --threshold 0.05

--output_relative_filenames는 traps/ 기준의 상대 경로를 쓰고, --include_image_timestamp는 각 이미지의 EXIF 시간을 datetime 필드에 복사합니다. --threshold 0.05는 MegaDetector의 보수적인 임계값까지 탐지를 유지합니다. 아래의 가져오기는 검토 자체의 기준값을 적용하므로, 나중에 다른 기준값을 시험하는 데 MegaDetector를 다시 실행할 필요가 없습니다. megadetector 패키지 10.0.28은 Apple silicon Mac에서 99장을 36초에 처리했고, 탐지기로 md_v5a.0.1.pt를 쓴 배치 출력 형식 1.6을 작성했습니다. 파일은 detector_metadata 아래에 MegaDetector의 일반적인 임계값 0.2를 기록합니다. 그 임계값에서 MegaDetector는 동물이 있는 64장 중 63장을 표시했고, 빈 이미지 35장 중 1장에 상자를 두었으며, 상자 80개를 남겼습니다.

데이터셋의 메타데이터는 각 시간을 +00:00 오프셋과 함께 제공하지만, 데이터셋의 파카(paca)는 18:00부터 05:00까지, 사람은 06:00부터 18:00까지 활동합니다. 따라서 카메라는 UTC보다 5시간 늦은 현지 시간을 기록했으며, 아래의 내보내기 단계가 이 오프셋을 더합니다.

카메라와 시퀀스 추가

MegaDetector의 출력은 각 이미지의 이름과 상자를 나열할 뿐 카메라나 시퀀스는 없습니다. Potato의 가져오기는 이미지 항목에 location, seq_id, frame_num 필드가 있으면 이를 읽습니다. 아래 스크립트는 각 경로의 첫 폴더에서 카메라를 가져오고, 60초가 넘는 간격 뒤에 새 시퀀스를 시작합니다.

python
import json
from collections import defaultdict
from datetime import datetime
 
results = json.load(open("md_output.json"))
 
# The first folder in each path is the camera, as in N29/105EK113/04110961.JPG
by_camera = defaultdict(list)
for image in results["images"]:
    image["location"] = image["file"].split("/")[0]
    by_camera[image["location"]].append(image)
 
# A new sequence starts when more than 60 seconds pass between two images
for camera, images in by_camera.items():
    images.sort(key=lambda im: im["datetime"])
    previous, n = None, 0
    for image in images:
        taken = datetime.strptime(image["datetime"], "%Y:%m:%d %H:%M:%S")
        if previous is None or (taken - previous).total_seconds() > 60:
            n += 1
            frame = 0
        image["seq_id"] = f"{camera}-{n:04d}"
        image["frame_num"] = frame
        frame += 1
        previous = taken
 
json.dump(results, open("md_output_seq.json", "w"), indent=1)
print(len(results["images"]), "images in",
      len({im["seq_id"] for im in results["images"]}), "sequences")

스크립트는 99 images in 33 sequences를 출력했으며, 33개 시퀀스는 데이터셋 자체의 시퀀스 ID와 일치했습니다.

결과를 Potato로 가져오기

카메라 트랩 시퀀스는 생태학자가 세는 단위인데, 카메라 앞을 세 프레임에 걸쳐 지나간 페커리는 한 번의 탐지이기 때문입니다. Potato를 설치하고 시퀀스당 항목 하나로 파일을 가져옵니다.

bash
pip install potato-annotation==2.12.1
potato import -i md_output_seq.json --image-dir traps --md-threshold 0.2 --sequences -o camera-trap-review/
text
Imported 33 item(s), 1 question(s), 0 answer(s) from 0 annotator(s), and 33 model suggestion(s) from MegaDetector batch output.
  left out: 19 detections below --md-threshold 0.2
  wrote camera-trap-review/data/md_output_seq.jsonl
  wrote camera-trap-review/config.yaml
  wrote camera-trap-review/README.md

각 시퀀스는 세 프레임의 갤러리로 표시되는 항목 하나가 되었고, 생성된 설정은 이미지를 복사하지 않고 traps/에서 제공합니다. 가져오기는 질문 하나인 triage를 씁니다. Potato는 시퀀스에서 가장 신뢰도가 높은 탐지로 답변을 미리 채우며, 0.2 이상의 탐지가 있는 프레임이 없으면 empty로 채웁니다. 미리 채워진 답변은 33개 시퀀스 모두에서 정답 키와 일치했습니다. MegaDetector는 종 이름을 붙이지 않습니다. 따라서 가져오기는 종 질문을 쓰지 않으며, 아래 설정이 하나를 추가합니다.

검토 설정

아래 설정은 가져오기가 쓴 설정에 네 가지를 바꿉니다. species 질문은 현장 목록의 종을 학명으로 나열하는데, Camtrap DP와 Darwin Core가 기록하는 것이 학명이기 때문입니다. humanize_labels: false는 이름을 쓴 그대로 유지하는데, 그렇지 않으면 Potato가 라벨을 제목 형식으로 바꿔 "Pecari Tajacu"로 표시하기 때문입니다. 분류(triage)에는 다음 절의 이유로 unidentified 옵션이 추가됩니다. num_annotators_per_item은 모든 시퀀스를 두 검토자에게 보내며, 처음 두 명이 불일치하면 시퀀스를 검토자 세 명으로 올립니다. 설정은 완전하며 2.12.1에서 python -m potato.validate_cli config.yaml --strict를 통과합니다.

yaml
annotation_task_name: Orinoquia camera traps, sequence review
task_dir: .
output_annotation_dir: annotation_output/
data_files:
  - data/md_output_seq.jsonl
item_properties:
  id_key: id
  text_key: seq_id
user_config:
  allow_all_users: true
  users: []
media_directory: /data/orinoquia/traps
 
instance_display:
  fields:
    - key: frames
      type: gallery
      label: Sequence
      display_options:
        layout: grid
        columns: 3
        show_captions: true
        zoomable: true
 
# Two volunteers review every sequence, and a sequence they disagree on goes to a third reviewer
num_annotators_per_item:
  default: 2
  adaptive:
    enabled: true
    disagreement_threshold: 0.5
    boost_to: 3
 
pre_annotation:
  enabled: true
  field: predictions
  allow_modification: true
 
annotation_schemes:
  - annotation_type: radio
    name: triage
    description: What does this sequence show?
    labels: [empty, animal, unidentified, person, vehicle]
    sequential_key_binding: true
 
  - annotation_type: multiselect
    name: species
    description: Which species appear in the sequence?
    humanize_labels: false
    labels:
      - Pecari tajacu
      - Tayassu pecari
      - Dasyprocta fuliginosa
      - Cuniculus paca
      - Nasua nasua
      - Tapirus terrestris
      - Mitu salvini
      - Myrmecophaga tridactyla
      - Leopardus pardalis
      - Bos taurus

가져오기는 --image-dir의 전체 경로를 media_directory로 쓰며, 여기서는 /data/orinoquia/traps로 표시되어 있습니다. 열 가지 종은 예시의 일곱 종에 큰개미핥기, 오셀롯, 소를 더한 것입니다. 추가한 세 종은 Orinoquía 세트의 다른 곳에 나타납니다. 열 이름 모두 GBIF 백본 분류 체계의 인정된 이름과 일치했습니다.

자원봉사자 검토와 전문가 확인

프로젝트 폴더에서 서버를 시작합니다.

bash
cd camera-trap-review
potato start config.yaml -p 8000

각 자원봉사자는 사용자 이름과 비밀번호로 등록하고, 1에서 5 키로 분류 답을 확인하고, 종을 체크합니다. 동물을 보았지만 종 이름을 붙이지 못하는 자원봉사자는 unidentified를 고르고 아무것도 체크하지 않습니다. 이 옵션이 Potato 2.12.1에서 중요한 이유는, 2.12.1이 한 질문에 대한 두 답변을 두 검토자가 모두 답을 준 경우에만 비교하기 때문입니다. 한 자원봉사자는 Nasua nasua를 체크하고 다른 자원봉사자는 아무것도 체크하지 않은 시퀀스는 비교할 종 답변이 없으며, 두 분류 답변은 모두 animal로 읽힙니다. 아래의 이미지 검토는 처음에 이 옵션 없이 실행했습니다. 그 실행에서 두 자원봉사자는 이미지 13장에서 의견이 갈렸고, Potato는 13장 중 5장만 세 번째 검토자에게 올렸습니다. Potato 2.13.1은 검토자가 항목을 떠난 뒤에는 빈 답변을 다른 답변으로 세므로 이 옵션은 더 이상 올리기에 필요하지 않으며, 이 옵션은 자원봉사자에게 동물 이름을 붙이지 못했다고 말할 방법을 여전히 줍니다.

전문가는 두 자원봉사자가 모두 끝난 뒤 한 번 로그인합니다. 다른 모든 시퀀스는 이미 두 검토자를 갖추었으므로, 서버는 전문가에게 불일치만 제공하고 다른 것은 주지 않습니다. 자원봉사자가 두 명보다 많으면, 올라간 시퀀스를 아직 보지 않은 자원봉사자가 전문가보다 먼저 세 번째 자리를 차지할 수 있습니다. Potato는 모든 자동 저장에서 답변을 비교하며, 페이지는 클릭 후 0.5초 뒤에 저장합니다. 잘못된 종을 체크했다가 체크를 고친 자원봉사자도 시퀀스를 전문가에게 보냅니다. 이런 수정은 전문가에게 시퀀스 하나를 더 보게 하는 비용이 듭니다.

테스트 실행에서 스크립트 자원봉사자 두 명은 동물 시퀀스의 15%와 10%에서 종 이름을 잘못 붙였습니다. 잘못된 답은 닮은 종이거나 unidentified였습니다. 첫 번째 자원봉사자는 6개 시퀀스에서, 두 번째는 4개에서 틀렸습니다. 자원봉사자들은 8개 시퀀스에서 의견이 갈렸고, Potato는 그 8개 시퀀스를 세 검토자에게 올렸으며, 전문가는 같은 8개를 받았습니다. 코아티(coati) 시퀀스 하나에서는 두 자원봉사자가 모두 unidentified를 골라서 시퀀스가 전문가에게 닿지 않았습니다. 같은 실수를 하는 두 자원봉사자는 일치하므로, 일치한 시퀀스도 무작위 표본으로 확인하세요.

패키지와 출현 기록 내보내기

Camtrap DP 패키지와 Darwin Core 출현 표를 한 폴더로 내보냅니다.

bash
python -m potato.export -c config.yaml -f camtrap_dp -o package/ \
    --option timezone=-05:00 --option contributor="Your Name" \
    --option sampling_design=systematicRandom --option capture_method=activityDetection
python -m potato.export -c config.yaml -f darwin_core -o package/ --option timezone=-05:00

첫 명령은 datapackage.json, deployments.csv, media.csv, observations.csv를 썼고, 두 번째는 occurrence.csv를 썼습니다. timezone=-05:00은 카메라 시간에 콜롬비아의 UTC 오프셋을 더합니다. Orinoquía의 카메라는 서로 1km 떨어져 있었고, 테스트 실행은 그 배치에 systematicRandom을 썼습니다. 직접 조사에 맞는 표본 설계를 Camtrap DP 목록에서 고르세요. 각 시퀀스는 이벤트 수준의 관찰을 주며, 시퀀스 ID가 eventID이고 첫 프레임과 마지막 프레임의 시간이 eventStart와 eventEnd입니다. 내보내기는 카메라 M04와 N29에 좌표가 없다고 경고했습니다. Camtrap DP는 모든 배치에 좌표를 요구합니다. --option license는 데이터 라이선스만 쓰고 다음 절의 스크립트가 프로필이 요구하는 두 라이선스를 쓰므로, 이 옵션은 빼세요.

Potato 2.12.1이 모든 검토자의 답변을 쓰기 때문에 두 표는 게시할 준비가 되어 있지 않습니다. observations.csv에는 시퀀스 33개에 대해 74행이 있었는데, 각 자원봉사자에서 시퀀스당 한 행이고 8개 시퀀스에서 전문가의 한 행이 더해진 것입니다. occurrence.csv에는 동물 시퀀스 23개에 대해 출현 46개가 있었습니다. Darwin Core에는 학명이 필요하므로 내보내기는 unidentified 답변 8개를 뺐습니다. 내보낸 그대로 게시하면 패키지가 각 동물을 두세 번 셀 것입니다. --option annotator=<user>는 여기서 도움이 되지 않는데, camtrap_dp와 darwin_core 내보내기는 이 옵션을 무시하고 megadetector 내보내기만 이 옵션을 읽기 때문입니다.

Potato 2.13.1은 두 표 모두에서 시퀀스당 검토자 한 명을 쓰며, --option annotator=<user>가 검토자를 지정하지 않으면 사용자 ID 순으로 첫 번째 검토자이고, 검토자들이 불일치한 시퀀스에 대해 경고합니다. 이 페이지의 저장된 검토에 실행했을 때 2.13.1은 관찰 33개와 출현 18개를 썼고 모두 첫 번째 자원봉사자의 것이었으므로, 불일치한 8개 시퀀스에 대한 전문가의 답변은 표에 없었습니다. 따라서 2.13.1 내보내기에도 전문가의 답변을 합치는 작업이 여전히 필요하며, 아래 스크립트가 2.12.1의 표에 대해 이를 합니다. 2.13.1에서 --option license=와 --option media_license=는 프로필이 요구하는 두 라이선스를 쓰고, 패키지는 Camtrap DP 1.0.2 프로필을 쓰며, --option media_base_url=은 Darwin Core의 associatedMedia를 공개 URL로 바꿉니다. 좌표는 여전히 직접 넣어야 합니다.

GBIF를 위한 패키지 준비

아래 스크립트는 시퀀스당 검토자 한 명의 답변을 유지합니다. 스크립트는 전문가가 시퀀스를 검토했다면 전문가의 답변을, 그렇지 않으면 사용자 이름이 앞서는 자원봉사자의 답변을 유지하는데, 전문가가 보지 않은 모든 시퀀스에서 두 자원봉사자가 일치했기 때문입니다. Potato는 각 observationID와 occurrenceID를 항목, 검토자, 번호를 콜론으로 이은 것으로 쓰며, 스크립트는 이 ID에서 검토자를 읽습니다. 그런 다음 스크립트는 Potato에 없는 사실을 추가합니다. 각 카메라의 좌표가 deployments.csv, occurrence.csv, 패키지의 spatial 상자에 들어갑니다. Camtrap DP 프로필은 라이선스가 하나라도 나열되면 두 범위를 모두 요구하므로, 데이터 라이선스와 미디어 라이선스가 datapackage.json에 들어갑니다. 로컬 경로는 공개 이미지 URL로 바뀝니다. 스크립트는 camera-trap-review/에서 실행하세요.

python
import csv
import json
from collections import defaultdict
 
EXPERT = "expert"
# Each camera's latitude and longitude in decimal degrees (WGS84)
CAMERAS = {"M04": (4.05, -71.95), "N29": (4.05, -71.95)}
# Where the images are public, if they are; "" keeps the local paths
MEDIA_BASE = "https://storage.googleapis.com/public-datasets-lila/orinoquia-camera-traps/public/"
DATA_LICENSE = "CC-BY-4.0"
MEDIA_LICENSE = "CDLA-Permissive-1.0"
 
 
def read(path):
    with open(path, newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        return reader.fieldnames, list(reader)
 
 
def write(path, columns, rows):
    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=columns)
        writer.writeheader()
        writer.writerows(rows)
 
 
def one_reviewer(rows, id_column):
    # Potato writes each ID as <item>:<reviewer>:<n>
    reviewers = defaultdict(set)
    for row in rows:
        item, reviewer, _ = row[id_column].rsplit(":", 2)
        reviewers[item].add(reviewer)
    # The expert's answer where the expert saw the item, otherwise the first volunteer's
    keep = {item: EXPERT if EXPERT in names else min(names) for item, names in reviewers.items()}
    return [row for row in rows
            if row[id_column].rsplit(":", 2)[1] == keep[row[id_column].rsplit(":", 2)[0]]]
 
 
columns, rows = read("package/observations.csv")
kept = one_reviewer(rows, "observationID")
write("package/observations.csv", columns, kept)
print("observations:", len(rows), "->", len(kept))
 
columns, rows = read("package/occurrence.csv")
kept = one_reviewer(rows, "occurrenceID")
for row in kept:
    lat, lon = CAMERAS[row["locationID"]]
    row.update(decimalLatitude=lat, decimalLongitude=lon, geodeticDatum="EPSG:4326")
    if MEDIA_BASE:
        row["associatedMedia"] = row["associatedMedia"].replace("/media/", MEDIA_BASE)
write("package/occurrence.csv", columns, kept)
print("occurrences:", len(rows), "->", len(kept))
 
columns, rows = read("package/deployments.csv")
for row in rows:
    row["latitude"], row["longitude"] = CAMERAS[row["deploymentID"]]
write("package/deployments.csv", columns, rows)
 
if MEDIA_BASE:
    columns, rows = read("package/media.csv")
    for row in rows:
        row["filePath"], row["filePublic"] = MEDIA_BASE + row["filePath"], "true"
    write("package/media.csv", columns, rows)
 
with open("package/datapackage.json", encoding="utf-8") as f:
    package = json.load(f)
lats = [lat for lat, _ in CAMERAS.values()]
lons = [lon for _, lon in CAMERAS.values()]
w, s, e, n = min(lons), min(lats), max(lons), max(lats)
package["spatial"] = {"type": "Polygon", "bbox": [w, s, e, n],
                      "coordinates": [[[w, s], [e, s], [e, n], [w, n], [w, s]]]}
package["licenses"] = [{"name": DATA_LICENSE, "scope": "data"},
                       {"name": MEDIA_LICENSE, "scope": "media"}]
# 1.0.2 has the same terms as 1.0, and current frictionless can read its profile
text = json.dumps(package, indent=2).replace("/camtrap-dp/1.0/", "/camtrap-dp/1.0.2/")
with open("package/datapackage.json", "w", encoding="utf-8") as f:
    f.write(text)

스크립트는 관찰을 74개에서 33개로, 출현을 46개에서 22개로 줄였습니다. 33개의 관찰은 이름이 붙은 동물 22개, 빈 시퀀스 10개, 두 자원봉사자가 unidentified로 남긴 코아티 시퀀스이며, 33개 중 32개가 정답 키와 일치합니다. EXPERT를 전문가의 사용자 이름으로, CAMERAS를 각 카메라 자체의 좌표로 바꾸세요. Orinoquía 데이터셋은 카메라 좌표를 공개하지 않으며, 테스트 실행은 두 카메라에 자리표시자 점 하나를 썼습니다. GBIF의 IPT 매뉴얼은 게시하는 데이터에 CC0, CC BY, CC BY-NC를 요청하고 뒤의 둘은 4.0 버전을 권장하므로, DATA_LICENSE는 이 세 라이선스 중에서 고르세요.

스크립트의 마지막 줄은 프로필 버전을 바꿉니다. Potato 2.12.1은 Camtrap DP 1.0 프로필 URL을 씁니다. Frictionless 5.17 이상은 1.0 프로필의 참조 하나를 해석하지 못하며, frictionless 5.21은 InvalidAnchor: '#$defs/version' is not a valid anchor 오류로 멈췄습니다. Camtrap DP 1.0.1은 어떤 용어도 바꾸지 않고 이 참조를 고쳤으며, 1.0.2가 현재 릴리스입니다. Camtrap DP 사이트가 제시하는 명령으로 패키지를 검증하세요.

bash
pip install frictionless
frictionless validate package/datapackage.json

Frictionless는 준비된 패키지의 세 표를 모두 VALID로 보고했습니다. 내보낸 그대로의 패키지에 같은 명령을 실행하면 프로필 URL에서, 그다음 빈 spatial 상자에서 실패했습니다. GBIF는 Camtrap DP 패키지를 R 패키지 camtrapdp로 읽으며, camtrapdp는 기본적으로 이벤트 수준 관찰에서 출현을 만듭니다. 시퀀스 검토는 이벤트 수준 관찰을 씁니다. camtrapdp 0.6.1은 준비된 패키지를 읽었고, check_camtrapdp()는 오류를 내지 않았으며, write_dwc()는 출현 23개를 썼습니다. 23개 중 22개는 종을 명시하고, 1개는 두 자원봉사자가 unidentified로 남긴 코아티 시퀀스에 대해 Animalia만 기록합니다. camtrapdp의 출력은 23개 모두의 basisOfRecord를 MachineObservation으로 주는데, Potato 자체의 darwin_core 내보내기는 사람이 한 동정에 HumanObservation을 씁니다. GBIF 게시자를 통해 패키지를 GBIF IPT 3 이상에 업로드하세요. 테스트 실행은 검증에서 멈췄으며 GBIF에는 아무것도 보내지 않았습니다.

수정된 상자 보관

프로젝트가 예를 들어 자체 현장에서 분류기를 학습시키려고 상자도 원한다면, 시퀀스 대신 개별 이미지를 검토하세요. --sequences 없이 가져오면 각 이미지가 MegaDetector의 상자가 미리 그려진 detections 상자 질문이 있는 항목 하나가 됩니다. 이미지 설정은 species 질문뿐 아니라 상자 라벨에도 종 이름을 추가합니다.

이미지 검토는 시퀀스 검토와 세 가지가 다릅니다. 첫째, Potato 2.12.1에는 기존 상자의 라벨을 바꾸는 컨트롤이 없고, Potato 2.13.1은 검토자가 종 라벨을 클릭하면 선택한 상자의 라벨을 바꿉니다. 2.12.1에서 라벨 버튼은 다음에 그리는 상자의 라벨을 정하며, MegaDetector의 상자 안에서 시작하는 드래그는 그 상자를 옮깁니다. 종 이름을 붙이려면 V와 클릭으로 MegaDetector의 상자를 선택하고, Delete를 누르고, 종을 고르고, R로 새 상자를 그리세요. 둘째, 각 이미지는 미디어 수준 관찰을 주므로 세 프레임에 나온 동물은 관찰 세 개가 됩니다. 셋째, camtrapdp는 datapackage.json에 "gbifIngestion": {"observationLevel": "media"}가 설정되어 있을 때만 미디어 수준 관찰을 읽습니다. 검증하기 전에 이 설정을 추가하세요. camtrapdp는 이 설정이 있으면 이미지 패키지를 출현 80개로 바꿨고 없으면 하나도 만들지 않았습니다. Potato 2.13.1은 개별 이미지 패키지에서 이 설정을 직접 씁니다.

이미지 실행은 같은 자원봉사자와 전문가를 썼습니다. Potato는 이미지 99장 중 13장을 전문가에게 올렸고, 내보내기는 관찰 247개를 썼습니다. 위의 스크립트는 247개를 115개로 줄였습니다. 115개는 종이 있는 상자 79개, MegaDetector가 놓친 이미지의 종 체크 1개, 빈 이미지 35개입니다. 한 시퀀스의 세 프레임에 나온 코아티는 이 관찰 중 세 개이며, 시퀀스 검토는 코아티를 한 번만 기록합니다.

python -m potato.export -c config.yaml -f megadetector -o export/는 MegaDetector 결과를 읽는 도구를 위해 항목당 검토자 한 명의 답변이 담긴 배치 출력 형식 1.4의 megadetector_reviewed.json을 씁니다. 기본 검토자는 사용자 ID 순으로 첫 번째이며, --option annotator=<user>는 다른 검토자를 지정합니다.

카메라 트랩 검토를 위한 다른 도구

AddaxAI는 Windows, Linux, 또는 Apple silicon Mac에서 설치 후 인터넷 연결 없이 MegaDetector와 지역 종 모델을 실행하고, Camtrap DP와 Timelapse 인식 파일로 내보냅니다. AddaxAI는 무료이며 일부 종 모델은 비상업적 라이선스이고, 이 프로그램은 이름이 바뀌기 전에는 EcoAssist였습니다. Timelapse는 이미지에 태그를 달기 위한 Windows 프로그램으로, AddaxAI와 MegaDetector 인식 파일을 가져와 상자를 그립니다. MegaDetector의 README는 MegaDetector와 함께 작동하는 플랫폼으로 Wildlife Insights, TrapTagger, Agouti, Camelot을 나열하며, Wildlife Insights는 기계 학습으로 업로드된 사진의 동물을 식별합니다. Potato는 여러 검토자가 브라우저에서 동정을 나누어 맡을 때, 각 검토자의 답변을 일치도를 위해 보관할 때, 이미지가 자신의 서버에 남아야 할 때 알맞습니다. 카메라 트랩과 생물음향 도구 비교는 이 도구들을 가격과 함께 나란히 놓고 비교합니다.

GBIF 게시에서 Potato의 한계

  • GBIF 내보내기에서 항목당 검토자 한 명. Potato 2.13.1에서 camtrap_dp와 darwin_core는 모든 항목에 대해 사용자 ID 순으로 첫 번째이거나 --option annotator가 지정한 검토자 한 명의 답변을 취하므로, 의견이 갈린 항목에 대한 전문가의 답변은 직접 합쳐야 합니다. Potato 2.12.1은 검토자당 관찰 하나를 썼습니다.
  • 좌표는 직접. Camtrap DP는 각 카메라의 좌표가 필요합니다. Potato 2.13.1은 latitude와 longitude가 포함된 MegaDetector 항목에서 이를 읽으며, Potato 2.12.1은 둘 다 읽지 않았습니다.
  • 종 모델 없음. Potato는 탐지기나 분류기를 실행하지 않습니다. MegaDetector의 classifications 필드에 있는 분류기의 종은 가져올 때 미리 채워진 라벨이 됩니다.
  • 시퀀스 검토에서 개체 수 없음. 이벤트 관찰은 count를 비워 둡니다.

다음으로 볼 자료

참고문헌

  1. Beery, S., Morris, D., & Yang, S. (2019). Efficient pipeline for camera trap image review. arXiv. https://arxiv.org/abs/1907.06772
  2. Vélez, J., McShea, W., Shamon, H., Castiblanco-Camacho, P. J., Tabak, M. A., Chalmers, C., Fergus, P., & Fieberg, J. (2023). An evaluation of platforms for processing camera-trap data using artificial intelligence. Methods in Ecology and Evolution, 14(2), 459-477. https://doi.org/10.1111/2041-210X.14044