demo.py로 MP4 파일을 직접 처리할 수 있습니다!
이 코드는 이미 MP4 파일을 직접 처리할 수 있도록 설계되어 있네요. `prepare_frames_or_path` 함수를 보면 MP4 파일이나 디렉토리 둘 다 입력으로 받을 수 있습니다.
사용 방법:
```bash
python demo.py \
--video_path input.mp4 \
--txt_path bbox.txt \
--video_output_path output.mp4
```
여기서 필요한 것은:
1. input.mp4: 추적하고 싶은 영상
2. bbox.txt: 각 프레임별 bounding box 정보가 담긴 텍스트 파일
- 형식: 각 줄마다 "x,y,w,h" (LaSOT 형식과 동일)
- 첫 프레임의 bbox가 추적 시작점이 됨
이 코드는 내부적으로:
1. MP4 파일을 자동으로 프레임으로 읽어들임
2. 메모리에 프레임들을 저장
3. SAM 모델로 추적 수행
4. 결과를 새로운 MP4 파일로 저장
따로 프레임을 추출하거나 디렉토리 구조를 만들 필요 없이, MP4 파일을 직접 입력으로 사용할 수 있습니다!
import cv2
def mouse_callback(event, x, y, flags, param):
global start_x, start_y, drawing, img_copy
if event == cv2.EVENT_LBUTTONDOWN: # 마우스 왼쪽 버튼 클릭
drawing = True
start_x, start_y = x, y
img_copy = img.copy()
elif event == cv2.EVENT_MOUSEMOVE: # 마우스 이동
if drawing:
temp_img = img_copy.copy()
cv2.rectangle(temp_img, (start_x, start_y), (x, y), (0, 255, 0), 2)
cv2.imshow('Select ROI', temp_img)
elif event == cv2.EVENT_LBUTTONUP: # 마우스 왼쪽 버튼 뗌
drawing = False
w = abs(x - start_x)
h = abs(y - start_y)
x_coord = min(start_x, x)
y_coord = min(start_y, y)
print(f"Bounding Box: x,y,w,h = {x_coord},{y_coord},{w},{h}")
# Save to bbox.txt
with open('bbox.txt', 'w') as f:
f.write(f"{x_coord},{y_coord},{w},{h}")
print("Coordinates saved to bbox.txt")
# 비디오 파일 열기
video_path = "extest.mp4" # 여기에 실제 비디오 경로 입력
cap = cv2.VideoCapture(video_path)
# 첫 프레임 읽기
ret, img = cap.read()
if not ret:
print("Error reading video")
exit()
# 윈도우 생성 및 마우스 콜백 설정
cv2.namedWindow('Select ROI')
cv2.setMouseCallback('Select ROI', mouse_callback)
# 전역 변수 초기화
drawing = False
start_x, start_y = -1, -1
img_copy = img.copy()
print("Select area with mouse. Press 'q' to quit.")
# 메인 루프
while True:
cv2.imshow('Select ROI', img_copy)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
SAMURAI 모델은 Zero-Shot 추적을 목표로 설계되었기 때문에, 특정 객체를 학습시키지 않고도 일반적인 객체 이동 패턴과 연속된 프레임 간 관계를 학습할 수 있습니다. LaSOT를 활용한 이유는 다음과 같습니다:
1. LaSOT를 학습에 사용하는 목적
LaSOT는 객체 추적 분야에서 널리 사용되는 벤치마크 데이터셋입니다. SAMURAI가 이 데이터셋을 학습하거나 평가에 사용하는 주요 목적은 다음과 같습니다:
1.1 Zero-Shot 추적 성능 평가
- SAMURAI는 특정 객체를 학습하지 않고도, 첫 프레임의 바운딩 박스를 기준으로 객체를 추적하는 모델입니다.
- LaSOT는 다양한 객체와 복잡한 상황(가림, 이동 속도 변화 등)을 포함하므로, SAMURAI가 이러한 상황에서 얼마나 잘 추적할 수 있는지를 평가하는 데 적합합니다.
- LaSOT의 역할: 모델의 성능을 측정하기 위한 테스트 데이터셋.
1.2 시간적 연속성 및 추적 알고리즘 개선
- LaSOT 데이터셋의 프레임 간 객체 움직임 데이터를 활용하여 모델이 시간적 연속성(temporal consistency)을 더 잘 이해하도록 설계할 수 있습니다.
- SAMURAI는 이동 패턴과 객체 외형의 변화를 일반화하여 학습합니다. 이 학습은 특정 객체를 기억하려는 것이 아니라, 프레임 간 객체의 이동과 변화를 추적하는 방법을 학습합니다.
2. 첫 프레임에서 바운딩 박스를 선택하는 방식
- LaSOT 데이터셋에서는 groundtruth.txt에 첫 프레임의 바운딩 박스가 포함되어 있으므로, SAMURAI는 실험에서 이 정보를 사용하여 추적을 시작합니다.
- 실제 응용에서는 사용자가 직접 선택한 바운딩 박스나 다른 모델이 자동으로 생성한 바운딩 박스를 입력으로 사용합니다.
3. LaSOT로 모델을 학습한 이유
LaSOT 데이터셋은 다양한 객체와 복잡한 추적 상황을 포함하기 때문에, SAMURAI와 같은 모델을 학습하거나 평가하기에 적합합니다. LaSOT를 사용한 학습 목적은 다음과 같습니다:
3.1 시간적 연속성 학습
- 모델은 LaSOT에서 프레임 간의 **객체 움직임, 외형 변화, 그리고 가림(occlusion)**과 같은 상황을 학습합니다.
- 이 과정에서 모델은 "주어진 바운딩 박스 안의 객체를 추적하는 일반적인 방법"을 학습합니다.
3.2 Zero-Shot 성능 강화
- SAMURAI는 특정 객체를 학습하는 것이 아니라, 객체 간의 일반적인 움직임 패턴과 프레임 간 상관관계를 학습합니다.
- LaSOT는 다양한 객체와 복잡한 시나리오를 포함하므로, 이러한 상황을 일반화하는 데 도움을 줍니다.
3.3 벤치마크 역할
- LaSOT는 모델 성능을 비교 평가할 수 있는 데이터셋으로도 활용됩니다.
- SAMURAI가 LaSOT에서 높은 추적 성능을 보이면, 이는 다양한 상황에서도 강력한 Zero-Shot 추적 모델임을 입증합니다.
4. SAMURAI는 학습된 객체를 추적하지 않는다
- SAMURAI는 특정 객체(예: 자동차, 사람 등)를 학습하지 않습니다.
- LaSOT는 SAMURAI가 "프레임 간의 연속적인 객체 추적" 능력을 학습하거나 평가하기 위해 사용됩니다.
- 실질적으로, SAMURAI는 첫 프레임의 바운딩 박스를 기준으로 동작하며, 특정 객체를 인식하거나 구분하지 않습니다.
5. 결론
LaSOT를 사용하는 이유는 첫 프레임에서 추적할 객체를 찾는 것이 아니라:
- 프레임 간의 객체 이동을 추적하는 방법을 학습하거나 평가하기 위해.
- Zero-Shot 성능을 강화하고, 다양한 상황에서의 추적 성능을 테스트하기 위해.
- 객체가 아닌, 추적 과정을 일반화할 수 있도록 도움을 주기 위해.
LaSOT는 SAMURAI와 같은 모델이 범용적인 객체 추적 능력을 갖출 수 있도록 돕는 도구로 사용됩니다.
맞습니다! SAMURAI 스크립트는 추적 작업의 중간 및 최종 결과를 여러 디렉토리로 저장합니다. 이 저장 경로는 각각의 작업 목적에 따라 구분되어 있습니다. 아래에 각 폴더와 그 역할을 정리해 보았습니다.
폴더 및 파일 설명
1. testing_set (테스트 비디오 목록 경로)
- 내용: 테스트에 사용할 비디오 파일명을 나열한 텍스트 파일(testing_set.txt).
- 역할:
- 추적할 비디오를 지정하는 데 사용됩니다.
- 예: airplane-1, person-10, squirrel-8 등이 포함.
2. checkpoint (모델 가중치 파일 경로)
- 내용: 사전 학습된 SAMURAI 모델의 가중치 파일(.pt).
- 역할:
- 추적 모델을 초기화하는 데 사용됩니다.
- 경로 예: sam2/checkpoints/sam2.1_hiera_base_plus.pt.
3. model_cfg (모델 설정 파일 경로)
- 내용: 모델의 구조 및 설정을 정의하는 YAML 파일.
- 역할:
- SAMURAI 모델의 구성을 정의합니다.
- 경로 예: configs/samurai/sam2.1_hiera_b+.yaml.
4. video_folder (비디오 데이터셋 디렉토리)
- 내용: LaSOT 데이터셋의 프레임 폴더 구조.
- 역할:
- 비디오 프레임 데이터를 제공하는 원본 경로.
- 경로 예:
data/LaSOT/ ├── airplane/ │ ├── airplane-1/ │ │ ├── img/ │ │ │ ├── 00000001.jpg │ │ │ ├── 00000002.jpg │ │ │ ├── ...
5. pred_folder (결과 예측값 저장 디렉토리)
- 내용: 각 비디오의 추적 결과를 저장한 텍스트 파일.
- 역할:
- 추적된 바운딩 박스를 텍스트 형식으로 저장합니다.
- 파일 내용 예:
120,150,80,100 125,155,80,100 130,160,80,100
- 경로 예:
results/samurai/samurai_base_plus/airplane-1.txt
6. vis_folder (결과 비디오 시각화 디렉토리)
- 내용: 추적된 결과를 오버레이한 비디오 파일(.mp4).
- 역할:
- 객체 추적 결과를 프레임 위에 시각화하여 저장합니다.
- 예: 추적된 객체의 바운딩 박스와 마스크를 오버레이.
- 경로 예:
visualization/samurai/base_plus/airplane-1.mp4
결론
- 추적 결과 시각화: vis_folder에 저장된 .mp4 파일은 추적된 객체를 프레임 위에 그려 보여줍니다.
- 추적 데이터 저장: pred_folder에 저장된 .txt 파일은 각 프레임에서의 바운딩 박스를 숫자로 저장합니다.
- 각 디렉토리는 모델 학습, 평가, 시각화를 위한 목적에 맞게 잘 구성되어 있습니다.
이 구조는 추적 과정을 명확히 분리해 주며, 결과 확인과 분석을 쉽게 만듭니다.
import cv2
import gc
import numpy as np
import os
import os.path as osp
import pdb
import torch
from sam2.build_sam import build_sam2_video_predictor
from tqdm import tqdm
def load_lasot_gt(gt_path):
with open(gt_path, 'r') as f:
gt = f.readlines()
# bbox in first frame are prompts
prompts = {}
fid = 0
for line in gt:
x, y, w, h = map(int, line.split(','))
prompts[fid] = ((x, y, x+w, y+h), 0)
fid += 1
return prompts
color = [
(255, 0, 0),
]
testing_set = "data/LaSOT/testing_set.txt"
with open(testing_set, 'r') as f:
test_videos = f.readlines()
exp_name = "samurai"
model_name = "base_plus"
checkpoint = f"sam2/checkpoints/sam2.1_hiera_{model_name}.pt"
if model_name == "base_plus":
model_cfg = "configs/samurai/sam2.1_hiera_b+.yaml"
else:
model_cfg = f"configs/samurai/sam2.1_hiera_{model_name[0]}.yaml"
video_folder= "data/LaSOT"
pred_folder = f"results/{exp_name}/{exp_name}_{model_name}"
save_to_video = True
if save_to_video:
vis_folder = f"visualization/{exp_name}/{model_name}"
os.makedirs(vis_folder, exist_ok=True)
vis_mask = {}
vis_bbox = {}
test_videos = sorted(test_videos)
for vid, video in enumerate(test_videos):
cat_name = video.split('-')[0]
cid_name = video.split('-')[1]
video_basename = video.strip()
frame_folder = osp.join(video_folder, cat_name, video.strip(), "img")
num_frames = len(os.listdir(osp.join(video_folder, cat_name, video.strip(), "img")))
print(f"\033[91mRunning video [{vid+1}/{len(test_videos)}]: {video} with {num_frames} frames\033[0m")
height, width = cv2.imread(osp.join(frame_folder, "00000001.jpg")).shape[:2]
predictor = build_sam2_video_predictor(model_cfg, checkpoint, device="cuda:0")
predictions = []
if save_to_video:
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(osp.join(vis_folder, f'{video_basename}.mp4'), fourcc, 30, (width, height))
# Start processing frames
with torch.inference_mode(), torch.autocast("cuda", dtype=torch.float16):
state = predictor.init_state(frame_folder, offload_video_to_cpu=True, offload_state_to_cpu=True, async_loading_frames=True)
prompts = load_lasot_gt(osp.join(video_folder, cat_name, video.strip(), "groundtruth.txt"))
bbox, track_label = prompts[0]
frame_idx, object_ids, masks = predictor.add_new_points_or_box(state, box=bbox, frame_idx=0, obj_id=0)
for frame_idx, object_ids, masks in predictor.propagate_in_video(state):
mask_to_vis = {}
bbox_to_vis = {}
assert len(masks) == 1 and len(object_ids) == 1, "Only one object is supported right now"
for obj_id, mask in zip(object_ids, masks):
mask = mask[0].cpu().numpy()
mask = mask > 0.0
non_zero_indices = np.argwhere(mask)
if len(non_zero_indices) == 0:
bbox = [0, 0, 0, 0]
else:
y_min, x_min = non_zero_indices.min(axis=0).tolist()
y_max, x_max = non_zero_indices.max(axis=0).tolist()
bbox = [x_min, y_min, x_max-x_min, y_max-y_min]
bbox_to_vis[obj_id] = bbox
mask_to_vis[obj_id] = mask
if save_to_video:
img = cv2.imread(f'{frame_folder}/{frame_idx+1:08d}.jpg')
if img is None:
break
for obj_id in mask_to_vis.keys():
mask_img = np.zeros((height, width, 3), np.uint8)
mask_img[mask_to_vis[obj_id]] = color[(obj_id+1)%len(color)]
img = cv2.addWeighted(img, 1, mask_img, 0.75, 0)
for obj_id in bbox_to_vis.keys():
cv2.rectangle(img, (bbox_to_vis[obj_id][0], bbox_to_vis[obj_id][1]), (bbox_to_vis[obj_id][0]+bbox_to_vis[obj_id][2], bbox_to_vis[obj_id][1]+bbox_to_vis[obj_id][3]), color[(obj_id)%len(color)], 2)
x1, y1, x2, y2 = prompts[frame_idx][0]
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
out.write(img)
predictions.append(bbox_to_vis)
os.makedirs(pred_folder, exist_ok=True)
with open(osp.join(pred_folder, f'{video_basename}.txt'), 'w') as f:
for pred in predictions:
x, y, w, h = pred[0]
f.write(f"{x},{y},{w},{h}\n")
if save_to_video:
out.release()
del predictor
del state
gc.collect()
torch.clear_autocast_cache()
torch.cuda.empty_cache()
코드 분석
이 코드는 **LaSOT 데이터셋을 활용한 객체 추적(Object Tracking)**을 수행하는 프로그램입니다. 주요 단계를 중심으로 분석해 보겠습니다.
1. 주요 라이브러리
- cv2: OpenCV, 비디오 및 이미지 처리에 사용.
- torch: PyTorch, 모델 로드 및 GPU 연산.
- tqdm: 진행 상태(progress bar) 시각화.
- numpy: 행렬 및 배열 연산.
- gc: 메모리 관리(가비지 컬렉션).
- os, os.path: 파일 및 디렉토리 경로 관리.
2. 주요 함수 및 변수
2.1 load_lasot_gt(gt_path)
- LaSOT 데이터셋의 ground truth 파일을 읽고, 각 프레임에서의 객체 바운딩 박스를 반환합니다.
- 반환 형식: {프레임 번호: ((x1, y1, x2, y2), 0)}.
2.2 주요 변수
- testing_set: 테스트에 사용할 비디오 목록을 저장한 파일 경로.
- checkpoint: SAMURAI 모델의 사전 학습된 가중치 파일.
- model_cfg: 모델 설정 파일 경로.
- video_folder: 비디오 데이터셋 디렉토리.
- pred_folder: 결과 예측값 저장 디렉토리.
- vis_folder: 결과 비디오 시각화 디렉토리.
3. 작업 흐름
- 테스트 데이터 준비
- testing_set 파일에서 테스트할 비디오 리스트를 읽습니다.
- 각 비디오에 대해 데이터 폴더 경로를 구성합니다.
- 비디오 처리 루프
- 비디오별로 처리:
- frame_folder: 비디오의 프레임 저장 디렉토리.
- num_frames: 해당 비디오의 총 프레임 수.
- height, width: 프레임 해상도.
- 비디오별로 처리:
- 모델 초기화
- build_sam2_video_predictor로 모델을 초기화합니다.
- 모델은 GPU(cuda:0)에서 실행되며, 설정 파일과 체크포인트를 활용합니다.
- 프레임 추적
- predictor.init_state: 초기 상태 설정.
- predictor.add_new_points_or_box: 초기 바운딩 박스 및 객체 ID 설정.
- predictor.propagate_in_video: 비디오 전체에 대해 추적을 수행하며, 각 프레임의 객체 마스크와 바운딩 박스를 추출합니다.
- 결과 저장
- 시각화:
- 객체 마스크와 바운딩 박스를 프레임에 그려 비디오로 저장.
- 텍스트 파일:
- 추적 결과(바운딩 박스)를 프레임별로 저장.
- 시각화:
4. 성능 및 최적화
- CUDA 및 GPU 활용
- PyTorch의 torch.autocast와 torch.inference_mode를 사용해 연산 속도를 높이고, 메모리 사용을 최적화.
- 메모리 관리
- 각 비디오 처리 후, gc.collect()와 torch.cuda.empty_cache()를 호출하여 GPU 메모리를 정리.
- 병렬화 가능성
- 현재 각 비디오를 순차적으로 처리하고 있습니다. 비디오 단위로 병렬 처리를 도입하면 전체 처리 시간을 줄일 수 있습니다.
- 모델 호출 최적화
- predictor.propagate_in_video 내에서의 병목 현상을 분석하고 최적화를 고려할 수 있습니다.
5. 개선 사항
- 병렬 처리
- multiprocessing 또는 concurrent.futures를 활용해 비디오를 병렬 처리.
- 로깅 개선
- 현재는 print를 사용해 진행 상태를 표시하지만, 로깅 라이브러리(logging)를 활용하면 디버깅이 더 편리.
- 프레임 처리 속도
- propagate_in_video 함수의 속도를 개선하거나 더 빠른 GPU를 활용.
6. 실행 결과
- 텍스트 파일:
- 각 프레임의 바운딩 박스 좌표를 기록한 결과 파일.
- 시각화 비디오:
- 추적된 객체의 마스크와 바운딩 박스가 시각화된 결과 비디오.
결론
이 코드는 SAMURAI 모델을 활용해 객체 추적을 수행하며, LaSOT 데이터셋의 테스트 세트를 처리합니다. 프레임 수준의 객체 추적 결과를 저장하고 시각화하는 기능을 포함합니다. 전체적으로 잘 구성된 코드이며, 병렬화 및 로깅 개선을 통해 추가적인 최적화가 가능합니다.
testing set
airplane-1
airplane-9
airplane-13
airplane-15
basketball-1
basketball-6
basketball-7
basketball-11
bear-2
bear-4
bear-6
bear-17
bicycle-2
bicycle-7
bicycle-9
bicycle-18
bird-2
bird-3
bird-15
bird-17
boat-3
boat-4
boat-12
boat-17
book-3
book-10
book-11
book-19
bottle-1
bottle-12
bottle-14
bottle-18
bus-2
bus-5
bus-17
bus-19
car-2
car-6
car-9
car-17
cat-1
cat-3
cat-18
cat-20
cattle-2
cattle-7
cattle-12
cattle-13
spider-14
spider-16
spider-18
spider-20
coin-3
coin-6
coin-7
coin-18
crab-3
crab-6
crab-12
crab-18
surfboard-12
surfboard-4
surfboard-5
surfboard-8
cup-1
cup-4
cup-7
cup-17
deer-4
deer-8
deer-10
deer-14
dog-1
dog-7
dog-15
dog-19
guitar-3
guitar-8
guitar-10
guitar-16
person-1
person-5
person-10
person-12
pig-2
pig-10
pig-13
pig-18
rubicCube-1
rubicCube-6
rubicCube-14
rubicCube-19
swing-10
swing-14
swing-17
swing-20
drone-13
drone-15
drone-2
drone-7
pool-12
pool-15
pool-3
pool-7
rabbit-10
rabbit-13
rabbit-17
rabbit-19
racing-10
racing-15
racing-16
racing-20
robot-1
robot-19
robot-5
robot-8
sepia-13
sepia-16
sepia-6
sepia-8
sheep-3
sheep-5
sheep-7
sheep-9
skateboard-16
skateboard-19
skateboard-3
skateboard-8
tank-14
tank-16
tank-6
tank-9
tiger-12
tiger-18
tiger-4
tiger-6
train-1
train-11
train-20
train-7
truck-16
truck-3
truck-6
truck-7
turtle-16
turtle-5
turtle-8
turtle-9
umbrella-17
umbrella-19
umbrella-2
umbrella-9
yoyo-15
yoyo-17
yoyo-19
yoyo-7
zebra-10
zebra-14
zebra-16
zebra-17
elephant-1
elephant-12
elephant-16
elephant-18
goldfish-3
goldfish-7
goldfish-8
goldfish-10
hat-1
hat-2
hat-5
hat-18
kite-4
kite-6
kite-10
kite-15
motorcycle-1
motorcycle-3
motorcycle-9
motorcycle-18
mouse-1
mouse-8
mouse-9
mouse-17
flag-3
flag-9
flag-5
flag-2
frog-3
frog-4
frog-20
frog-9
gametarget-1
gametarget-2
gametarget-7
gametarget-13
hand-2
hand-3
hand-9
hand-16
helmet-5
helmet-11
helmet-19
helmet-13
licenseplate-6
licenseplate-12
licenseplate-13
licenseplate-15
electricfan-1
electricfan-10
electricfan-18
electricfan-20
chameleon-3
chameleon-6
chameleon-11
chameleon-20
crocodile-3
crocodile-4
crocodile-10
crocodile-14
gecko-1
gecko-5
gecko-16
gecko-19
fox-2
fox-3
fox-5
fox-20
giraffe-2
giraffe-10
giraffe-13
giraffe-15
gorilla-4
gorilla-6
gorilla-9
gorilla-13
hippo-1
hippo-7
hippo-9
hippo-20
horse-1
horse-4
horse-12
horse-15
kangaroo-2
kangaroo-5
kangaroo-11
kangaroo-14
leopard-1
leopard-7
leopard-16
leopard-20
lion-1
lion-5
lion-12
lion-20
lizard-1
lizard-3
lizard-6
lizard-13
microphone-2
microphone-6
microphone-14
microphone-16
monkey-3
monkey-4
monkey-9
monkey-17
shark-2
shark-3
shark-5
shark-6
squirrel-8
squirrel-11
squirrel-13
squirrel-19
volleyball-1
volleyball-13
volleyball-18
volleyball-19
SAMURAI 프로젝트는 **"Segment Anything Model for Zero-Shot Visual Tracking"**을 목표로 하며, 다양한 객체에 대한 범용적 추적이 가능하도록 설계되었습니다. 공식적으로 제공된 설명 및 코드는 특정 객체에 국한되지 않고, 사용자가 원하는 대상을 설정할 수 있습니다.
이슈: 왜 person이 없나?
- testing_set.txt의 제한
- testing_set.txt 파일에 포함된 객체는 사용자가 추적 대상으로 지정한 객체입니다.
- 제공된 파일에는 person 객체가 포함되지 않았으므로, 실행 시 사람에 대한 추적이 수행되지 않습니다.
- SAMURAI 모델의 범용성
- SAMURAI는 특정 객체를 미리 학습하지 않아도, 첫 프레임의 바운딩 박스를 기준으로 추적을 수행합니다.
- 따라서, person을 추적하려면 테스트 세트에 관련 데이터를 추가하거나, 커스텀 비디오에서 직접 demo.py를 실행해야 합니다.
사람 추적이 가능한 이유
SAMURAI의 주요 특성은 범용적인 객체 추적입니다:
- 입력 비디오와 첫 프레임의 바운딩 박스(txt_path)만 제공하면, 어떤 객체라도 추적 가능합니다.
- 이를 통해 person과 같은 객체를 포함한 다양한 추적이 가능합니다.
사람을 추가하려면?
- testing_set.txt 수정
- person 비디오 파일명을 추가합니다:
person-1 person-5 person-10 person-12
- LaSOT 데이터셋 디렉토리에 해당 비디오 파일과 관련 데이터를 준비합니다.
- person 비디오 파일명을 추가합니다:
- 커스텀 비디오로 실행
- 사람을 포함한 임의의 비디오를 추적하려면, 다음 명령어를 사용하세요:
python scripts/demo.py --video_path <your_video.mp4> --txt_path <path_to_first_frame_bbox.txt>
- 여기서 <path_to_first_frame_bbox.txt>는 첫 프레임의 바운딩 박스를 정의한 파일입니다.
- 사람을 포함한 임의의 비디오를 추적하려면, 다음 명령어를 사용하세요:
결론
SAMURAI는 사람을 포함한 모든 객체를 추적할 수 있습니다. testing_set.txt는 단순히 특정 객체로 구성된 테스트 세트를 정의하며, 사람 추적은 가능합니다. 테스트 세트에 사람 비디오를 추가하거나, 커스텀 비디오를 활용해 추적 작업을 수행하면 됩니다.
1. 주요 정보
비디오 처리 상태
- 총 비디오 수: [280] 중에서 현재 [237]번째 비디오를 처리하고 있습니다.
- 현재 비디오 이름: 각 단계에서 처리 중인 비디오 이름은 squirrel-11, squirrel-13, squirrel-19, squirrel-8, surfboard-12 등입니다.
- 비디오별 프레임 수:
- squirrel-11: 9999 프레임
- squirrel-13: 1449 프레임
- squirrel-19: 2000 프레임
- squirrel-8: 1205 프레임
- surfboard-12: 1041 프레임
프레임 처리 속도
- Frame Loading:
- JPEG 프레임 로딩 속도는 약 25~30 FPS로 안정적입니다.
- 예: squirrel-11의 9999 프레임은 약 6분(6:09) 만에 로딩 완료.
- Propagation:
- Propagation(추적) 속도는 약 8~9 FPS입니다.
- 예: squirrel-11의 9999 프레임은 약 20분(20:29) 만에 처리 완료.
처리 속도의 변동성
- Propagation 단계는 처리 비디오 및 프레임 수에 따라 약간의 차이를 보입니다:
- squirrel-8: 9.22 FPS
- surfboard-12: 7.88 FPS
이 차이는 영상 해상도나 GPU 성능에 따른 병목 현상, 혹은 객체 복잡도에 기인할 수 있습니다.
2. 해석
처리 대상
- testing_set.txt 파일에 포함된 비디오만 추적 대상으로 처리됩니다. 이 경우 squirrel, surfboard 관련 비디오가 포함되어 처리되고 있습니다.
성능 평가
- Frame Loading 단계는 안정적으로 높은 속도를 유지하고 있으나, Propagation 단계에서 상대적으로 속도가 낮아집니다. 이는 주로:
- 모델 복잡도 (SAMURAI의 세분화된 추적 알고리즘)
- GPU 자원 부족 (특히 비디오 해상도가 높거나 많은 객체가 있는 경우)
- 추적 과정의 병목 등 때문일 수 있습니다.
3. 개선 가능성
병렬 처리
현재 비디오들은 순차적으로 처리되고 있습니다. 비디오 단위로 병렬화(multi-threading 또는 multi-processing)를 도입하면 전체 처리 시간을 단축할 수 있습니다.
추적 알고리즘 최적화
Propagation 속도를 높이기 위해 GPU 메모리 관리나 PyTorch 모델 최적화를 고려할 수 있습니다:
- torch.backends.cudnn.benchmark = True 설정 추가
- 더 나은 CUDA 연산 활용
추적 대상 축소
모든 프레임을 처리할 필요가 없는 경우, 예를 들어 n 프레임마다 추적하거나 해상도를 줄여 처리 속도를 높일 수 있습니다.
결론
- 이 결과는 SAMURAI가 설정한 비디오 리스트에서 지정된 객체를 추적하고 있음을 보여줍니다.
- 시스템 성능 및 알고리즘 최적화를 통해 더 빠른 추적이 가능할 것으로 보입니다.
- 현재 테스트 세트의 구성상 **사람(person)**은 추적 대상에 포함되지 않은 상태이며, 필요 시 테스트 세트를 수정해 포함할 수 있습니다.
LaSOT 데이터셋은 실제로 개별 이미지 파일(jpg) 형태로 저장되어 있지만, SAMURAI 스크립트는 이를 비디오로 처리하는 방식으로 작동합니다.
왜 LaSOT 이미지 데이터셋을 비디오처럼 처리할까?
- 이미지 기반 데이터셋의 구조
- LaSOT는 각 비디오를 구성하는 프레임들을 별도의 JPG 이미지 파일로 저장합니다.
- 예: airplane-1은 img/00000001.jpg, img/00000002.jpg 등으로 구성됩니다.
- 비디오처럼 처리하는 이유
- SAMURAI 모델은 비디오 객체 추적을 목표로 설계되었으며, 객체의 이동 궤적을 학습하고 추론하는 데 최적화되어 있습니다.
- 이를 위해 프레임 간의 시간적 연속성을 유지해야 하므로, 개별 이미지를 비디오처럼 순차적으로 처리합니다.
- 프레임 로딩과 Propagation
- 프레임 로딩 단계: 이미지 파일을 순서대로 로드하여 비디오의 프레임처럼 다룹니다.
- Propagation 단계: 연속된 프레임 간의 객체 이동을 추적합니다.
- SAMURAI 모델은 프레임 간의 변화를 인식하고, 추적 대상의 마스크와 바운딩 박스를 연속적으로 업데이트합니다.
- 결과 저장
- 최종 결과를 **비디오 파일(mp4)**로 저장하거나, 추적 결과를 텍스트 파일로 내보낼 수 있습니다.
실제 동작 방식
LaSOT 데이터셋에서의 처리 방식은 다음과 같습니다:
데이터 구조
data/LaSOT
├── airplane/
│ ├── airplane-1/
│ │ ├── img/
│ │ │ ├── 00000001.jpg
│ │ │ ├── 00000002.jpg
│ │ │ ├── ...
│ │ ├── groundtruth.txt
│ │ ├── full_occlusion.txt
│ │ ├── out_of_view.txt
│ │ ├── nlp.txt
스크립트 작동 과정
- 프레임 로딩:
- cv2.imread()로 각 JPG 이미지를 읽고 비디오 프레임처럼 메모리에 로드합니다.
- 이미지 파일명을 기반으로 순서를 보장합니다.
- 비디오 추적:
- 첫 프레임의 객체 위치(바운딩 박스)를 **groundtruth.txt**에서 읽어 옵니다.
- 모델은 프레임 간의 이동을 추적하여 각 프레임에서의 마스크와 바운딩 박스를 생성합니다.
- 결과 저장:
- 추적 결과를 시각화하여 **비디오(mp4)**로 저장.
- 예측된 바운딩 박스를 **텍스트 파일(csv)**로 저장.
장점과 단점
장점
- 이미지 데이터셋을 비디오처럼 활용함으로써 비디오 추적 알고리즘을 그대로 적용할 수 있습니다.
- 데이터셋 구조를 변경하지 않고도 시간적 연속성을 고려한 모델 평가가 가능합니다.
단점
- JPG 이미지를 순차적으로 읽고 처리하므로 처리 시간이 늘어날 수 있습니다.
- GPU 메모리와 CPU 성능의 병목이 발생할 가능성이 있음.
결론
SAMURAI는 LaSOT 데이터셋의 JPG 이미지를 비디오처럼 처리하여, 시간적 연속성을 고려한 객체 추적을 수행합니다. 이 접근 방식은 데이터셋 구조를 변경하지 않고 비디오 기반 추적 모델을 평가하는 데 매우 적합합니다.
C:\GitHub\samurai\results\samurai\samurai_base_plus\airplane-1
364,102,43,14
365,105,44,12
362,107,45,12
361,110,45,13
361,112,45,14
361,115,45,13
364,117,44,13
364,119,45,13
361,121,46,13
358,120,46,13
357,120,44,13
360,122,44,13
360,126,45,12
360,126,44,12
360,127,44,13
356,128,44,13
353,129,45,12
352,129,44,12
351,128,44,13
348,128,44,12
346,127,44,13
345,125,44,14
344,125,46,13
344,125,45,13
주어진 데이터는 비디오의 각 프레임에서 추적된 객체의 바운딩 박스 좌표를 저장한 결과입니다. 파일에 저장된 데이터 형식과 의미는 다음과 같습니다:
데이터 형식
- 각 줄은 한 프레임에서의 객체 위치를 나타냅니다.
- 포맷: x,y,w,h
- x: 바운딩 박스의 왼쪽 상단 모서리의 x 좌표
- y: 바운딩 박스의 왼쪽 상단 모서리의 y 좌표
- w: 바운딩 박스의 너비 (width)
- h: 바운딩 박스의 높이 (height)
예시
364,102,43,14
365,105,44,12
362,107,45,12
- 1번째 줄: 바운딩 박스의 좌표는 (x=364, y=102)이고, 크기는 (너비=43, 높이=14)입니다.
- 2번째 줄: (x=365, y=105)에서 (너비=44, 높이=12).
- 3번째 줄: (x=362, y=107)에서 (너비=45, 높이=12).
파일의 의미
- 이 파일은 SAMURAI 모델이 추적한 객체의 프레임별 위치를 기록한 데이터셋입니다.
- airplane-1 비디오에 대해 SAMURAI가 추적한 결과로, 첫 번째 프레임부터 마지막 프레임까지의 바운딩 박스 좌표가 기록되어 있습니다.
사용 목적
- 평가
- 실제 groundtruth.txt와 비교하여 추적 성능(정확도, IoU 등)을 평가할 수 있습니다.
- 추적 시각화
- 비디오의 각 프레임에 해당 바운딩 박스를 시각화하여 추적 결과를 확인할 수 있습니다.
- 추가 분석
- 바운딩 박스의 크기 변화, 객체의 이동 궤적 등 시간에 따른 객체의 특성을 분석할 수 있습니다.
추가 작업
이 데이터를 활용하여 다음과 같은 분석을 수행할 수 있습니다:
- 프레임별 이동 거리 계산
- 이전 프레임과 현재 프레임의 바운딩 박스 중심점 간의 거리를 계산.
- 추적 품질 평가
- groundtruth.txt와 비교하여 정확도, 정밀도, 재현율 계산.
- 시각화
- OpenCV를 사용해 비디오 프레임에 바운딩 박스를 그린 결과를 확인.
필요하면 데이터 분석이나 시각화를 도와드릴 수 있습니다! 😊
import argparse
import os
import os.path as osp
import numpy as np
import cv2
import torch
import gc
import sys
sys.path.append("./sam2")
from sam2.build_sam import build_sam2_video_predictor
color = [(255, 0, 0)]
def load_txt(gt_path):
with open(gt_path, 'r') as f:
gt = f.readlines()
prompts = {}
for fid, line in enumerate(gt):
x, y, w, h = map(float, line.split(','))
x, y, w, h = int(x), int(y), int(w), int(h)
prompts[fid] = ((x, y, x + w, y + h), 0)
return prompts
def determine_model_cfg(model_path):
if "large" in model_path:
return "configs/sam2.1/sam2.1_hiera_l.yaml"
elif "base_plus" in model_path:
return "configs/sam2.1/sam2.1_hiera_b+.yaml"
elif "small" in model_path:
return "configs/sam2.1/sam2.1_hiera_s.yaml"
elif "tiny" in model_path:
return "configs/sam2.1/sam2.1_hiera_t.yaml"
else:
raise ValueError("Unknown model size in path!")
def prepare_frames_or_path(video_path):
if video_path.endswith(".mp4") or osp.isdir(video_path):
return video_path
else:
raise ValueError("Invalid video_path format. Should be .mp4 or a directory of jpg frames.")
def main(args):
model_cfg = determine_model_cfg(args.model_path)
predictor = build_sam2_video_predictor(model_cfg, args.model_path, device="cuda:0")
frames_or_path = prepare_frames_or_path(args.video_path)
prompts = load_txt(args.txt_path)
if args.save_to_video:
if osp.isdir(args.video_path):
frames = sorted([osp.join(args.video_path, f) for f in os.listdir(args.video_path) if f.endswith(".jpg")])
loaded_frames = [cv2.imread(frame_path) for frame_path in frames]
height, width = loaded_frames[0].shape[:2]
else:
cap = cv2.VideoCapture(args.video_path)
loaded_frames = []
while True:
ret, frame = cap.read()
if not ret:
break
loaded_frames.append(frame)
cap.release()
height, width = loaded_frames[0].shape[:2]
if len(loaded_frames) == 0:
raise ValueError("No frames were loaded from the video.")
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(args.video_output_path, fourcc, 30, (width, height))
with torch.inference_mode(), torch.autocast("cuda", dtype=torch.float16):
state = predictor.init_state(frames_or_path, offload_video_to_cpu=True)
bbox, track_label = prompts[0]
_, _, masks = predictor.add_new_points_or_box(state, box=bbox, frame_idx=0, obj_id=0)
for frame_idx, object_ids, masks in predictor.propagate_in_video(state):
mask_to_vis = {}
bbox_to_vis = {}
for obj_id, mask in zip(object_ids, masks):
mask = mask[0].cpu().numpy()
mask = mask > 0.0
non_zero_indices = np.argwhere(mask)
if len(non_zero_indices) == 0:
bbox = [0, 0, 0, 0]
else:
y_min, x_min = non_zero_indices.min(axis=0).tolist()
y_max, x_max = non_zero_indices.max(axis=0).tolist()
bbox = [x_min, y_min, x_max - x_min, y_max - y_min]
bbox_to_vis[obj_id] = bbox
mask_to_vis[obj_id] = mask
if args.save_to_video:
img = loaded_frames[frame_idx]
for obj_id, mask in mask_to_vis.items():
mask_img = np.zeros((height, width, 3), np.uint8)
mask_img[mask] = color[(obj_id + 1) % len(color)]
img = cv2.addWeighted(img, 1, mask_img, 0.2, 0)
for obj_id, bbox in bbox_to_vis.items():
cv2.rectangle(img, (bbox[0], bbox[1]), (bbox[0] + bbox[2], bbox[1] + bbox[3]), color[obj_id % len(color)], 2)
out.write(img)
if args.save_to_video:
out.release()
del predictor, state
gc.collect()
torch.clear_autocast_cache()
torch.cuda.empty_cache()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--video_path", required=True, help="Input video path or directory of frames.")
parser.add_argument("--txt_path", required=True, help="Path to ground truth text file.")
parser.add_argument("--model_path", default="sam2/checkpoints/sam2.1_hiera_base_plus.pt", help="Path to the model checkpoint.")
parser.add_argument("--video_output_path", default="demo.mp4", help="Path to save the output video.")
parser.add_argument("--save_to_video", default=True, help="Save results to a video.")
args = parser.parse_args()
main(args)
이 스크립트는 SAMURAI 모델을 활용하여 객체 추적 결과를 비디오 또는 이미지에 시각화하는 데 사용됩니다. 아래는 스크립트의 주요 흐름과 역할을 분석한 내용입니다.
주요 기능
- 입력 파일 처리:
- --video_path: 입력으로 사용할 비디오 파일 경로 또는 프레임 이미지가 저장된 디렉토리 경로.
- --txt_path: 첫 번째 프레임의 바운딩 박스를 포함한 텍스트 파일 경로.
- --model_path: SAMURAI 모델의 체크포인트 파일 경로.
- --video_output_path: 추적 결과를 저장할 비디오 경로.
- 바운딩 박스 및 마스크 시각화:
- 추적된 객체의 마스크와 바운딩 박스를 프레임에 그려 저장합니다.
- 결과 저장:
- 결과를 비디오 파일(.mp4)로 저장합니다.
스크립트 분석
1. 함수 설명
- load_txt(gt_path)
- Ground Truth 파일(.txt)을 읽고 첫 프레임의 바운딩 박스 정보를 가져옵니다.
- 반환 값은 각 프레임 번호에 대한 바운딩 박스 좌표와 ID:
{frame_idx: ((x_min, y_min, x_max, y_max), track_label)}
- determine_model_cfg(model_path)
- 모델 체크포인트 경로를 분석하여 적절한 YAML 설정 파일 경로를 반환합니다.
- prepare_frames_or_path(video_path)
- 입력 경로가 비디오 파일(.mp4)인지, 프레임 이미지 디렉토리인지 확인.
- main(args)
- SAMURAI 모델로 객체 추적을 수행하며, 추적 결과를 비디오로 시각화하여 저장.
2. 주요 흐름
- 모델 초기화
- determine_model_cfg로 설정 파일 경로를 결정.
- build_sam2_video_predictor를 사용해 SAMURAI 모델 초기화.
- 프레임 로딩
- 비디오 파일이면 OpenCV를 사용해 모든 프레임을 메모리에 로드.
- 이미지 디렉토리라면 프레임 파일 이름을 정렬하여 로드.
- 추적 초기화
- 첫 프레임의 바운딩 박스를 설정(prompts[0]).
- predictor.add_new_points_or_box를 호출하여 추적 시작.
- 추적 수행
- predictor.propagate_in_video를 사용해 프레임별 추적 수행.
- 각 프레임에서:
- 객체 마스크를 생성하고 이를 시각화.
- 바운딩 박스를 생성하여 프레임에 그립니다.
- 결과 저장
- 결과를 비디오(args.video_output_path)로 저장.
추가 작업
- 시각화된 결과 비디오 생성
- --video_path에 지정된 비디오나 이미지 디렉토리의 프레임에 대해 추적 결과를 오버레이한 비디오 생성.
- 결과 비디오는 --video_output_path에 저장됩니다.
- 커스텀 데이터 처리
- Ground Truth 텍스트 파일(--txt_path)의 형식이 (x, y, w, h)인 경우만 작동합니다.
- 다른 형식의 데이터셋에 사용하려면 텍스트 파일의 형식을 조정해야 합니다.
- 다양한 모델 활용
- --model_path를 변경하여 다른 크기의 SAMURAI 모델(large, base_plus, small, tiny)을 사용할 수 있습니다.
실행 예시
비디오 입력
python demo.py --video_path input_video.mp4 --txt_path first_frame_bbox.txt --video_output_path output_video.mp4
이미지 디렉토리 입력
python demo.py --video_path ./frames/ --txt_path first_frame_bbox.txt --video_output_path output_video.mp4
결론
- 이 스크립트는 SAMURAI 모델을 사용해 객체 추적을 수행하고, 시각화된 결과를 비디오로 저장하는 데 사용됩니다.
- LaSOT와 같은 프레임 기반 데이터셋과 MP4 비디오를 모두 지원하며, 사용자 정의 데이터에도 쉽게 적용할 수 있습니다.
- 입력 데이터 형식과 모델 경로만 올바르게 지정하면 다양한 추적 작업에 활용 가능합니다.
SAMURAI 모델은 LaSOT 데이터셋에 포함된 객체의 종류와 상관없이, 사람을 포함한 모든 객체를 추적할 수 있습니다.
SAMURAI는 특정 객체(예: 사람, 자동차, 동물 등)에 대한 학습이 아니라, 프레임 간의 객체 이동을 일반화하는 추적 알고리즘이기 때문입니다.
왜 LaSOT 학습셋만으로 사람을 추적할 수 있는가?
- Zero-Shot 추적 능력:
- SAMURAI는 "첫 프레임에서 주어진 바운딩 박스"를 기준으로 동작하며, 추적할 객체의 종류(사람, 자동차 등)에 영향을 받지 않습니다.
- 즉, 사람이든 자동차든 첫 프레임의 객체 위치가 주어지면, SAMURAI는 모든 객체를 범용적으로 추적할 수 있습니다.
- LaSOT의 일반적인 학습 데이터:
- LaSOT는 다양한 객체(사람 포함)의 이동, 크기 변화, 가림(occlusion) 등을 포함한 프레임 간 상관관계를 학습하게 돕습니다.
- SAMURAI는 이 데이터로 특정 객체를 학습하지 않고, 시간적 연속성과 객체 이동 패턴을 일반화합니다.
- 추적할 객체의 초기 정보 제공:
- SAMURAI는 첫 프레임의 바운딩 박스만 있으면, **새로운 객체(사람 포함)**를 학습 없이 추적할 수 있습니다.
- 예를 들어, LaSOT에 포함되지 않은 "사람"도 첫 프레임의 위치 정보만 있다면 추적이 가능합니다.
사람을 추적하려면 어떻게 해야 하는가?
1단계: 사람을 포함한 비디오 준비
- 비디오 파일(source.mp4) 또는 프레임 디렉토리(frames/)를 준비합니다.
- 첫 번째 프레임에서 사람이 포함된 영역을 수동으로 지정하거나, 다른 도구를 사용해 바운딩 박스를 정의합니다.
2단계: 첫 프레임 바운딩 박스 정의
- OpenCV 등의 도구를 사용하여 사람이 포함된 바운딩 박스를 얻습니다:
import cv2 cap = cv2.VideoCapture('source.mp4') ret, frame = cap.read() cap.release() bbox = cv2.selectROI("Select Person", frame, fromCenter=False, showCrosshair=True) cv2.destroyAllWindows() print("Bounding box:", bbox) # 예: (x, y, w, h)
- 결과를 텍스트 파일(first_frame_bbox.txt)로 저장합니다:
100,150,80,120
3단계: SAMURAI 실행
- 준비한 비디오와 바운딩 박스를 SAMURAI에 입력하여 실행합니다:
python demo.py --video_path source.mp4 --txt_path first_frame_bbox.txt --video_output_path output_video.mp4
사람 추적의 한계와 가능성
- 한계:
- SAMURAI는 일반적인 추적 모델이므로, 객체의 외형 변화가 매우 크거나, 추적 중 객체가 완전히 가려지는 경우 성능이 떨어질 수 있습니다.
- 예: 사람이 다른 객체 뒤로 완전히 가려지거나, 카메라 밖으로 벗어난 경우.
- 가능성:
- 사람을 포함한 다양한 객체를 학습 없이 추적할 수 있습니다.
- LaSOT 외에도 추가 데이터셋 없이, 실제 비디오에서도 사용 가능합니다.
결론
LaSOT 학습셋만으로도 SAMURAI는 사람을 충분히 추적할 수 있습니다.
이것은 SAMURAI의 범용적인 Zero-Shot 추적 능력 덕분이며, 추가 데이터셋 없이도 사람을 포함한 거의 모든 객체를 추적할 수 있습니다.
다만, 초기 바운딩 박스를 정확히 설정해 주는 것이 중요합니다. 🚀
동영상에서 여러 사람 중 한 사람만을 추적하려면, 첫 프레임에서 원하는 사람의 바운딩 박스만 선택해야 합니다. SAMURAI는 선택된 객체만 추적하므로, 다른 사람은 자동으로 무시됩니다. 아래에 방법을 단계별로 정리했습니다.
1. 첫 프레임에서 원하는 사람만 선택하기
방법 1: OpenCV를 사용해 수동으로 선택
- OpenCV의 selectROI() 함수를 사용하여 동영상의 첫 프레임에서 추적할 사람을 선택할 수 있습니다:
- import cv2 # 비디오 로드 cap = cv2.VideoCapture('source.mp4') ret, frame = cap.read() cap.release() # 객체 선택 bbox = cv2.selectROI("Select the Person to Track", frame, fromCenter=False, showCrosshair=True) cv2.destroyAllWindows() # 바운딩 박스 좌표 출력 print("Selected bounding box:", bbox) # (x, y, w, h)
- 결과 예:
- Bounding box: (100, 150, 80, 120)
- 이 값을 텍스트 파일로 저장하여 SAMURAI에 입력합니다:
- 100,150,80,120
방법 2: 다른 도구 사용 (GUI 기반)
- OpenCV 외에도 GUI 기반의 비디오 편집 도구를 사용해 첫 프레임에서 사람의 바운딩 박스를 수동으로 지정할 수 있습니다.
- 지정한 바운딩 박스를 텍스트 파일 형식(x, y, w, h)으로 변환하여 SAMURAI에 입력합니다.
2. SAMURAI에 입력하여 특정 사람 추적
- 텍스트 파일 준비
- 원하는 사람의 바운딩 박스 정보를 텍스트 파일로 저장합니다:
first_frame_bbox.txt
- 원하는 사람의 바운딩 박스 정보를 텍스트 파일로 저장합니다:
- SAMURAI 실행
- 선택된 바운딩 박스를 기준으로 SAMURAI를 실행:
python demo.py --video_path source.mp4 --txt_path first_frame_bbox.txt --video_output_path output_video.mp4
- 선택된 바운딩 박스를 기준으로 SAMURAI를 실행:
3. 여러 사람이 나오는 장면에서의 추가 고려사항
추적 대상 간의 겹침 또는 가림
- 만약 선택한 사람이 다른 사람 뒤로 가려지거나, 다른 사람과 겹친다면 추적이 어려워질 수 있습니다.
- 이 경우 SAMURAI는 다음과 같은 방식을 사용합니다:
- 이전 프레임의 정보를 기반으로 추적: 객체의 이동 궤적을 예측하여 추적 지속.
- 다른 객체와의 차별화: 크기, 색상, 위치 등의 차이를 고려하여 올바른 객체를 추적.
특정 사람의 ID를 계속 유지하기
- SAMURAI는 프레임 간 추적을 통해 객체 ID를 유지합니다. 처음 선택한 바운딩 박스의 ID(obj_id=0)를 지속적으로 추적합니다.
4. 여러 사람을 동시에 추적하려면?
- SAMURAI는 기본적으로 여러 객체를 동시에 추적할 수 있습니다.
- 이를 위해 각 객체의 바운딩 박스를 입력으로 제공해야 합니다:
python demo.py --video_path source.mp4 --txt_path multiple_bboxes.txt --video_output_path output_video.mp4
- 예시 multiple_bboxes.txt:
100,150,80,120 # 사람 1 200,100,60,110 # 사람 2
결론
- 여러 사람 중 한 명만 추적하려면, 첫 프레임에서 해당 사람의 바운딩 박스를 정확히 지정하면 됩니다.
- SAMURAI는 지정된 바운딩 박스를 기준으로 동작하며, 다른 사람은 자동으로 무시됩니다.
- 선택한 사람과 다른 사람이 겹치는 상황에서도 SAMURAI는 일반적으로 추적을 지속할 수 있습니다.
필요하다면 바운딩 박스 선택 자동화 또는 GUI를 활용해 더 쉽게 작업할 수도 있습니다. 😊
이슈를 해결하기 위해 SAMURAI 모델과 관련된 몇 가지 사항과 접근 방법을 확인해볼 수 있습니다. SAMURAI 모델은 정확도를 보장하는 데 데이터 특성에 따라 성능이 크게 영향을 받을 수 있습니다. 특히, 첫 프레임 기준 트래킹의 경우에는 다음과 같은 요인들이 영향을 미칠 수 있습니다.
1. 첫 프레임의 오브젝트 정보 품질
- 첫 프레임에서 선택된 **오브젝트 정보(바운딩 박스)**가 정확하지 않을 경우, 이후 프레임에서 모델의 성능이 저하될 수 있습니다.
- 바운딩 박스가 너무 좁거나 너무 넓으면 모델이 정확히 트래킹하지 못할 수 있으므로, 정확한 초기 바운딩 박스를 제공하는 것이 중요합니다.
- 해결 방법:
- 첫 프레임에서 수동으로 더 정확한 바운딩 박스를 지정해보세요.
- 초기 프레임에서 오브젝트 크기와 위치를 조금 더 정밀하게 조정한 뒤 트래킹을 실행합니다.
2. 영상 데이터의 특성
- LaSOT 데이터셋은 모델 학습 및 평가를 위해 잘 구성된 데이터셋이지만, 실제 영상에서는 데이터의 품질이 달라질 수 있습니다.
- 조명 변화, 배경 클러터, 오클루전 등이 트래킹 성능에 영향을 줄 수 있습니다.
- 해결 방법:
- 모델이 작동하는 데이터를 분석하여 LaSOT 데이터셋과 차이를 확인하세요.
- 필요하다면 비슷한 특성을 가진 데이터로 추가 학습(파인튜닝)을 수행합니다.
3. 모델의 하이퍼파라미터 조정
- 모델이 동작하는 방식은 하이퍼파라미터에 따라 달라질 수 있습니다.
- demo.py에서 설정된 탐색 영역 크기, 학습률, 업데이트 빈도 등을 조정하면 성능이 개선될 수 있습니다.
- 해결 방법:
- demo.py에서 설정된 기본 파라미터를 확인하고, 아래 사항을 시도하세요:
- 탐색 영역 크기(search_region): 오브젝트를 찾는 범위를 확대하거나 축소.
- 업데이트 빈도(update_interval): 프레임마다 오브젝트 특성을 업데이트하는 빈도.
- demo.py에서 설정된 기본 파라미터를 확인하고, 아래 사항을 시도하세요:
4. 모델의 강건성 부족
- SAMURAI 모델이 첫 프레임 트래킹에 대해 충분히 학습되지 않았을 가능성도 있습니다.
- 학습 데이터가 부족하거나, 특정 환경에 과적합되었다면 트래킹 성능이 저하될 수 있습니다.
- 해결 방법:
- LaSOT과 비슷한 형식으로 추가 데이터를 준비하여 모델을 재학습합니다.
- 또는, 사전 학습된 가중치를 초기화하고 다시 학습합니다.
5. demo.py 코드 수정
- demo.py는 모델의 기본 데모를 보여주기 위한 간단한 코드로 작성되어 있을 가능성이 높습니다.
- 예를 들어, 매 프레임에서의 업데이트 전략이나 바운딩 박스 크기 보정 알고리즘을 수정하여 성능을 개선할 수 있습니다.
- 해결 방법:
- 코드에서 트래킹 실패 시 오브젝트 재탐색 기능을 추가해보세요.
- 예: 특정 프레임에서 오브젝트를 잃어버린 경우, 이전 위치를 기준으로 탐색 영역을 확대하는 전략을 구현.
6. 시각적 디버깅
- 프레임마다 오브젝트 위치를 저장하고, 시각적으로 확인하세요. 트래킹 실패 원인을 명확히 파악할 수 있습니다.
- 해결 방법:
- 결과를 저장하여 프레임별 바운딩 박스가 어떻게 변화하는지 확인합니다.
- 트래킹이 실패하는 구간에서 모델의 입력을 확인하고, 모델이 잘못 학습된 부분을 수정합니다.
7. 대체 모델 또는 추가 기술 사용
- 단순히 SAMURAI 모델로만 트래킹이 잘 안 된다면, 이를 보완하기 위해 다중 모델을 활용하는 방법도 고려할 수 있습니다.
- 예: SAMURAI와 함께 디텍터 기반 모델(YOLO 등)을 결합하여 트래킹 실패 시 재탐색을 수행.
LaSOT 데이터셋은 **객체 추적(Object Tracking)**을 위해 각 프레임을 체계적으로 나누고, 각 프레임별로 오브젝트의 위치를 정확히 기록한 구조로 구성되어 있습니다. LaSOT의 데이터 구조와 프레임 및 오브젝트 정보 기록 방식은 아래와 같습니다:
1. LaSOT 데이터셋 구조
LaSOT 데이터셋은 비디오와 각 프레임에 대한 객체 위치 정보를 포함합니다. 일반적인 폴더 구조는 다음과 같습니다:
LaSOT/
│
├── train/ (훈련 데이터)
│ ├── video1/
│ │ ├── img/
│ │ │ ├── 00000001.jpg
│ │ │ ├── 00000002.jpg
│ │ │ ├── ...
│ │ ├── groundtruth.txt
│ │ └── other_metadata.txt
│ ├── video2/
│ │ ├── img/
│ │ ├── groundtruth.txt
│ │ └── ...
│ └── ...
├── test/ (테스트 데이터)
│ ├── video1/
│ ├── video2/
│ └── ...
2. 프레임 분리
- 비디오는 각 프레임으로 분리되어 .jpg 형식으로 저장됩니다.
- 프레임 이름은 8자리 숫자로 구성되며(예: 00000001.jpg), 이는 순서에 따라 정렬됩니다.
3. 오브젝트 위치 기록 방식
LaSOT 데이터셋은 각 프레임의 오브젝트 위치를 텍스트 파일(groundtruth.txt)에 기록합니다. 이 파일은 다음과 같은 형식을 사용합니다:
groundtruth.txt 형식
x1,y1,w,h
x2,y2,w,h
x3,y3,w,h
...
- x, y: 객체의 좌측 상단 꼭짓점 좌표 (픽셀 단위).
- w, h: 객체의 너비(Width)와 높이(Height) (픽셀 단위).
예시:
75,100,50,80
76,101,50,81
78,103,50,83
4. 다른 메타데이터
추가적인 메타데이터 파일(other_metadata.txt)에는 비디오의 프레임 수, 객체 이름, 카테고리, 프레임 속도 등이 포함됩니다. 형식은 다음과 같습니다:
other_metadata.txt
name: car
category: vehicle
frame_rate: 30
num_frames: 1000
5. 객체 위치 기록 자동화 방법
LaSOT 데이터셋에서 오브젝트 위치를 기록하는 작업은 보통 반자동 또는 자동 도구를 사용하여 수행되었습니다. 일반적으로 다음 절차를 따릅니다:
절차
- 초기 바운딩 박스 설정:
- 비디오의 첫 프레임에서 수동으로 객체의 위치를 지정합니다.
- 객체 추적 알고리즘 사용:
- 기본 객체 추적 알고리즘(예: MedianFlow, Siamese Tracker 등)을 사용해 나머지 프레임에서 객체를 추적합니다.
- 수동 검토 및 수정:
- 알고리즘이 잘못 추적한 경우, 수동으로 바운딩 박스를 수정합니다.
- 텍스트 파일 생성:
- 모든 프레임의 바운딩 박스를 저장하여 groundtruth.txt 파일을 생성합니다.
6. 프레임별 데이터 분석 코드 예시
Python을 사용해 LaSOT 데이터의 groundtruth.txt 파일을 읽고 시각화하는 간단한 코드 예시는 다음과 같습니다:
import cv2
# 비디오 경로
video_path = "LaSOT/train/video1/img/"
groundtruth_path = "LaSOT/train/video1/groundtruth.txt"
# Groundtruth 읽기
with open(groundtruth_path, "r") as f:
bboxes = [list(map(int, line.strip().split(','))) for line in f.readlines()]
# 비디오 프레임 처리
for idx, bbox in enumerate(bboxes):
frame_path = f"{video_path}{idx+1:08d}.jpg" # 00000001.jpg 형식
frame = cv2.imread(frame_path)
if frame is None:
continue
# Bounding box 그리기
x, y, w, h = bbox
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 프레임 표시
cv2.imshow("Frame", frame)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
7. LaSOT 데이터셋 다운로드
LaSOT 데이터셋은 공식 홈페이지에서 LaSOT에서 다운로드할 수 있습니다.
이 방식은 각 프레임별로 오브젝트 위치를 체계적으로 기록하고, 이후 모델 학습 및 평가에 사용할 수 있도록 설계되었습니다. 추가적인 질문이 있다면 말씀해주세요!
LaSOT와 같은 데이터셋을 만드는 것은 객체 추적 연구를 위한 고품질 데이터셋을 생성하는 과정으로, 비디오 데이터를 준비하고, 프레임별로 객체 정보를 기록하며, 데이터셋을 구조화하는 작업이 필요합니다. 아래는 LaSOT 스타일의 데이터셋을 만드는 방법을 단계적으로 설명한 가이드입니다.
1. 비디오 데이터 준비
(1) 소스 비디오 수집
- 객체 추적 연구에 적합한 다양한 비디오를 수집합니다.
- 다양한 환경 (실내, 실외, 조명 변화 등)
- 다양한 객체 (사람, 차량, 동물 등)
- 다양한 시나리오 (정지, 이동, 오클루전 등)
(2) 영상 포맷 통일
- 모든 비디오를 동일한 포맷으로 변환합니다.
- 권장 포맷: .mp4, .avi
- 해상도: 최소 720p 이상
- 프레임 속도(FPS): 30 fps 권장
2. 비디오를 프레임 이미지로 분리
(1) Python 스크립트를 사용하여 분리
Python의 OpenCV 라이브러리를 사용하여 비디오를 프레임 이미지로 분리합니다:
import cv2
import os
def video_to_frames(video_path, output_folder):
# 폴더 생성
os.makedirs(output_folder, exist_ok=True)
# 비디오 캡처
cap = cv2.VideoCapture(video_path)
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
# 프레임 저장
frame_filename = os.path.join(output_folder, f"{frame_count:08d}.jpg")
cv2.imwrite(frame_filename, frame)
frame_count += 1
cap.release()
print(f"Extracted {frame_count} frames to {output_folder}")
# 예제 사용
video_to_frames("input_video.mp4", "output_frames/")
- 결과물: output_frames/ 디렉토리에 00000001.jpg, 00000002.jpg 등의 프레임 이미지가 저장됩니다.
3. 객체의 위치(바운딩 박스) 정의
(1) 첫 프레임에서 객체 위치 지정
- 첫 번째 프레임에서 객체의 위치를 사람이 수동으로 정의합니다.
- 툴 사용:
- LabelImg: 바운딩 박스를 수동으로 지정할 수 있는 툴.
- Roboflow 또는 CVAT: 인터페이스가 더 직관적이고 효율적입니다.
(2) 나머지 프레임 자동 추적
- 객체 추적 알고리즘을 사용하여 나머지 프레임에서 객체를 추적합니다.
- 추천 알고리즘:
- MedianFlow
- KCF
- Siamese Tracker
- OpenCV의 추적기 (cv2.Tracker API)
- 추천 알고리즘:
Python으로 구현 예제:
import cv2
import os
def track_object(video_path, initial_bbox, output_folder):
cap = cv2.VideoCapture(video_path)
tracker = cv2.TrackerKCF_create() # 다른 트래커 사용 가능
# 첫 번째 프레임 초기화
ret, frame = cap.read()
tracker.init(frame, initial_bbox)
frame_count = 0
os.makedirs(output_folder, exist_ok=True)
while True:
ret, frame = cap.read()
if not ret:
break
# 객체 추적
ret, bbox = tracker.update(frame)
if ret:
x, y, w, h = [int(v) for v in bbox]
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 바운딩 박스 저장
with open(os.path.join(output_folder, "groundtruth.txt"), "a") as f:
f.write(f"{x},{y},{w},{h}\n")
frame_filename = os.path.join(output_folder, f"{frame_count:08d}.jpg")
cv2.imwrite(frame_filename, frame)
frame_count += 1
cap.release()
print("Tracking completed")
# 사용 예제
video_path = "input_video.mp4"
initial_bbox = (75, 100, 50, 80) # x, y, width, height
output_folder = "tracked_frames/"
track_object(video_path, initial_bbox, output_folder)
4. 데이터 검증 및 수정
(1) 추적 결과 검토
- 바운딩 박스의 위치와 크기가 정확한지 시각적으로 확인합니다.
- 수정이 필요한 경우, 수동으로 텍스트 파일(groundtruth.txt)을 편집하거나 GUI 툴을 사용하여 수정합니다.
(2) 오클루전 및 객체 손실 처리
- 객체가 가려지는 경우나 프레임에서 사라지는 경우를 -1,-1,-1,-1로 기록.
5. 데이터셋 구조화
LaSOT과 같은 구조로 데이터를 정리합니다:
CustomDataset/
├── train/
│ ├── video1/
│ │ ├── img/
│ │ │ ├── 00000001.jpg
│ │ │ ├── 00000002.jpg
│ │ │ ├── ...
│ │ ├── groundtruth.txt
│ │ └── metadata.txt
│ ├── video2/
│ └── ...
├── test/
│ ├── video1/
│ ├── video2/
│ └── ...
(1) groundtruth.txt
프레임별 바운딩 박스 좌표를 저장 (위에서 생성한 형식).
(2) metadata.txt
각 비디오의 메타데이터를 기록:
name: car
category: vehicle
frame_rate: 30
num_frames: 100
6. 테스트
데이터셋을 실제 객체 추적 모델에 입력하여 성능을 확인하고, 필요한 경우 데이터 품질을 조정합니다.
위 과정을 따라 데이터셋을 만들면 LaSOT처럼 구조화된 고품질의 객체 추적 데이터셋을 생성할 수 있습니다.
LaSOT 데이터셋의 생성 과정과 작업 기록에 대한 자세한 정보는 공식 논문과 관련 자료에서 확인하실 수 있습니다. LaSOT는 2019년 CVPR에서 발표된 "LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking" 논문에서 소개되었습니다. 이 논문에서는 데이터셋의 구축 과정, 구성, 그리고 평가 방법 등에 대해 상세히 설명하고 있습니다.
공식 논문 및 자료:
- 논문 제목: LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking
- 발표 학회: CVPR 2019
- 논문 링크: https://arxiv.org/abs/1809.07845
또한, LaSOT 데이터셋은 Hugging Face의 Datasets 라이브러리에서도 제공되고 있으며, 해당 페이지에서 데이터셋의 구성과 다운로드 방법 등을 확인하실 수 있습니다.
Hugging Face Datasets 페이지:
이러한 자료들을 통해 LaSOT 데이터셋의 작업 기록과 생성 과정에 대한 상세한 정보를 얻으실 수 있습니다.
논문 요약: LaSOT - A High-quality Benchmark for Large-scale Single Object Tracking
논문 정보
- 제목: LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking
- 발표 학회: CVPR 2019
- 링크: 논문 보기
1. 연구 배경
- **단일 객체 추적(Single Object Tracking)**은 컴퓨터 비전의 중요한 분야로, 다양한 응용(감시, 자율주행, 로봇공학)에 활용됩니다.
- 기존 데이터셋은 작은 규모와 짧은 길이의 비디오로 인해, 모델의 실제 성능을 평가하기에 한계가 있었습니다.
- 이를 해결하기 위해 LaSOT 데이터셋을 제안하며, 이는 대규모, 고품질의 긴 비디오 클립으로 구성되어 객체 추적 모델의 강건성과 일반화를 평가할 수 있습니다.
2. LaSOT 데이터셋의 특징
- 대규모:
- 총 1,400개 비디오와 3.52M 프레임으로 구성.
- 기존 데이터셋(OTB, VOT 등)보다 훨씬 큼.
- 긴 비디오:
- 비디오당 평균 길이는 약 2,500 프레임, 이는 기존 데이터셋보다 10배 이상 긴 수준.
- 다양한 객체:
- 70개 객체 카테고리(예: 사람, 차량, 동물 등).
- 실제 환경에서 발생하는 다양한 시나리오를 포함.
- 도전적인 시나리오:
- 다양한 도전 과제 포함:
- 조명 변화 (Lighting Changes)
- 배경 혼란 (Background Clutter)
- 오클루전 (Occlusion)
- 스케일 변화 (Scale Variation)
- 움직임 불연속성 (Abrupt Motion)
- 다양한 도전 과제 포함:
3. 데이터 생성 과정
- 비디오 수집:
- 실제 환경에서 촬영된 비디오를 사용.
- 길이와 시나리오 복잡성을 고려하여 비디오를 선택.
- 객체 주석:
- 첫 번째 프레임에서 객체의 정확한 바운딩 박스를 사람이 수동으로 정의.
- 객체 추적 알고리즘(반자동)을 활용해 나머지 프레임을 자동 추적.
- 수동 검토 및 수정을 통해 데이터 품질 보장.
- 다양한 시나리오 커버:
- 조명 변화, 오클루전 등 현실적인 시나리오를 포함하여 데이터셋의 복잡성을 높임.
4. LaSOT의 데이터 구성
- 훈련(Train) 세트:
- 1,120개의 비디오.
- 추적 모델 학습에 사용.
- 테스트(Test) 세트:
- 280개의 비디오.
- 모델 평가를 위한 독립적인 테스트 세트.
- 주석 형식:
- 각 프레임의 객체 위치를 x, y, w, h(좌측 상단 좌표와 너비, 높이)로 기록.
- 오클루전 상황은 특수 태그를 추가.
5. 평가 방법
- LaSOT는 기존 데이터셋에서 제공되지 않았던 다양한 성능 평가 지표를 제공합니다.
- 정확도(Precision): 객체 위치가 얼마나 정확히 추적되었는지.
- 성공률(Success): 객체와 바운딩 박스의 겹침 영역(IoU) 기반.
- 장시간 추적 성능: 긴 비디오에서의 모델 성능을 평가.
6. 실험 결과
- 기존의 대표적인 객체 추적 모델(SiamFC, ECO, MDNet 등)을 LaSOT에서 평가.
- 결과:
- 대부분의 모델은 긴 비디오와 복잡한 시나리오에서 성능이 저하됨.
- 이는 기존 데이터셋에서 학습된 모델이 일반화 성능이 부족하다는 것을 보여줌.
- LaSOT는 모델의 강건성과 일반화 능력을 더 잘 평가할 수 있음을 입증.
7. 주요 기여
- 대규모 데이터셋 제안:
- LaSOT는 기존 데이터셋의 한계를 극복하고, 더 다양한 시나리오와 긴 비디오를 제공.
- 장시간 추적 평가:
- 장시간 비디오에서 객체 추적 모델의 성능을 측정하는 새로운 기준을 제시.
- 모델 한계 분석:
- 기존 모델의 성능이 복잡한 환경에서 크게 저하된다는 점을 실험적으로 검증.
8. 결론 및 미래 방향
- LaSOT는 객체 추적 연구를 위한 새로운 기준점을 제공하며, 기존 데이터셋 대비 더 현실적이고 도전적인 평가 환경을 제공합니다.
- 앞으로 더 다양한 객체와 추적 시나리오를 포함하는 방향으로 데이터셋을 확장할 계획.
핵심 요약
- LaSOT는 객체 추적 연구의 새로운 기준을 제시하는 대규모, 고품질 데이터셋입니다.
- 장시간 추적과 다양한 시나리오에서의 평가를 가능하게 하며, 기존 모델의 한계를 드러냅니다.
- 객체 추적 모델의 강건성과 일반화 성능을 측정하는 데 매우 유용한 도구로 자리 잡았습니다.
추가적인 질문이나 세부 내용을 원하시면 말씀해주세요!
'OpenSRC+ChatGPT' 카테고리의 다른 글
[WEB] 화면 캡쳐해서 PDF 로 뽑기. (0) | 2023.03.28 |
---|---|
simd_float4x4 (0) | 2021.01.14 |
App Store 정보 18.Dec.2020 (0) | 2020.12.18 |
previousPinchRecogScale (0) | 2020.12.14 |
pkg mng system. brew -> port (0) | 2020.11.27 |
최근댓글