Paper : TCTrack: Temporal Contexts for Aerial Tracking (Ziang Cao, Ziyuan Huang, Liang Pan, Shiwei Zhang, Ziwei Liu, Changhong Fu / CVPR 2022)
online temporal adaptive convolution
은 이전 frame의 정보를 통해 convolution weight를 매번 조정하여, 이전 프레임의 정보를 활용해 현재 프레임을 강화adaptive temporal transformer
는 이전 프레임에서 temporal knowledge를 효율적으로 encoding하여, target object와 현재 frame이 얼마나 matching되는지를 나타내는 similarity map을 refineTemporal Context
란 시간에 따른 frame으로부터 추출되는 정보나 관계를 의미 → 연속되는 frame에서의 변화나 패턴을 활용하여 tracking 정확도 및 robustness를 향상시키기 위함 → 여기서 변화나 패턴이라 함은 아래의 내용들을 의미 TAdaConv
(Temporal adaptive convolution)에서는 temporal context를 고려하여 feature를 추출한다.
TAdaConv
의 output은 아래와 같다.standard conv
가 학습된 파라미터를 모든 tracking sequence에 똑같이 적용하는 것과 다르게, online conv layer
에서는 학습된 파라미터 ()와 각 frame마다 다른 calibration factor를 이용하여 파라미터를 재계산한다.temporal context queue
를 계속해서 keep하며, 이를 통해 past time의 temporal context를 고려Calibration factor
를 생성하기 위해서 temporal context queue 에 두 번의 conv ()를 적용similarity map
를 구할 수 있다.AT-Trans
는 temporal context를 고려하여 feature extraction process에서 얻어진 similarity map을 refinement
AT-Trans
는 encoder-decoder 구조d는 scale factor
N은 head 수 (AT-Trans에서는 6)
Transformer는 CNN에 비해서 global context 정보를 더욱 효율적으로 encoding할 수 있음
특히 AT-Trans에서는 temporal knowledge의 online update strategy를 사용하여 불필요한 연산을 제거
AT-Trans의 encoder는 current similarity map
와 이전 knowledge
를 결합하여 temporal prior knowledge
를 생성
두 번의 MHA
, Temporal information filter
, 그리고 한번의 MHA
를 더 거쳐서 생성
temporal prior knowledge
을 query로, current similarity map
를 value로 사용해 attention block에 대입
→ current similarity map
에 더욱 중요도를 부여한다고 함
즉, 번째 frame의 stacked MHA layer
output 는 아래와 같이 구해진다.
feed-forward network
를 활용한다.MHA
를 한번 더 적용해서 번째 frame의 temporal knowledge
를 구할 수 있다.이렇게하면, temporal knowledge를 모두 저장하지 않고, 각 frame마다 매번 update할 수 있고, memory를 절약할 수 있다.
추가적으로, tracking sequence의 첫번째 frame의 similarity map은 target object의 semantic feature에 대한 정보를 잘 담고 있을 것이라는 가정 하에, initial temporal prior
는 initial similarity map
에 conv를 적용하여 구한다.
Decoder는 temporal prior knowledge를 가지고, similarity map을 정제한다.
현재 spatial feature 와 prior knowledge 의 interrelation을 고려하기 위해서 2개의 MHA
와 FFN
을 활용
Attention을 통해 prior knowledge에서 유용한 정보만을 추출해서 similarity map을 정제할 수 있음
그러면 최종 output은 아래와 같이 구할 수 있다
→ TCTracker
는 다양한 문제에 대해서 robust
→ 27 FPS로 작동
for idx, (img, gt_bbox) in enumerate(video):
tic = cv2.getTickCount()
if idx == 0:
cx, cy, w, h = get_axis_aligned_bbox(np.array(gt_bbox))
gt_bbox_ = [cx-(w-1)/2, cy-(h-1)/2, w, h]
tracker.init(img, gt_bbox_)
pred_bbox = gt_bbox_
scores.append(None)
if 'VOT2018-LT' == args.dataset:
pred_bboxes.append([1])
else:
pred_bboxes.append(pred_bbox)
else:
outputs = tracker.track(img,hp)
pred_bbox = outputs['bbox']
pred_bboxes.append(pred_bbox)
scores.append(outputs['best_score'])
tracker.init(img, gt_bbox_)
tracker.init
에서는 bounding box 좌표를 활용해 image의 target object 부분을 crop하고 model의 template으로 등록def init(self, img, bbox):
"""
args:
img(np.ndarray): BGR image
bbox: (x, y, w, h) bbox
"""
self.image=img
self.center_pos = np.array([bbox[0]+(bbox[2]-1)/2,
bbox[1]+(bbox[3]-1)/2])
self.size = np.array([bbox[2], bbox[3]])
# calculate z crop size
w_z = self.size[0] + cfg.TRACK.CONTEXT_AMOUNT * np.sum(self.size)
h_z = self.size[1] + cfg.TRACK.CONTEXT_AMOUNT * np.sum(self.size)
s_z = round(np.sqrt(w_z * h_z))
self.scaleaa=s_z
# calculate channle average
self.channel_average = np.mean(img, axis=(0, 1))
# get crop
z_crop = self.get_subwindow(img, self.center_pos,
cfg.TRACK.EXEMPLAR_SIZE,
s_z, self.channel_average)
self.template=z_crop
s_x = s_z * (cfg.TRACK.INSTANCE_SIZE / cfg.TRACK.EXEMPLAR_SIZE)
x_crop = self.get_subwindow(img, self.center_pos,
cfg.TRACK.INSTANCE_SIZE,
round(s_x), self.channel_average)
self.model.template(z_crop,x_crop)
z_crop
: target object의 reference template을 의미
x_crop
: network의 search region을 의미
self.model.template
에서는 backbone으로부터 feature를 추출하고, 이를 template으로 등록
def template(self, z,x):
with t.no_grad():
zf,_,_ = self.backbone.init(z)
self.zf=zf
xf,xfeat1,xfeat2 = self.backbone.init(x)
ppres=self.grader.conv1(self.xcorr_depthwise(xf,zf))
self.memory=ppres
self.featset1=xfeat1
self.featset2=xfeat2
Initial temporal prior
는 initial similarity map
에 conv를 수행하여 도출 ppres=self.grader.conv1(self.xcorr_depthwise(xf,zf))
self.memory
가 temporal prior knowledge를 의미
self.backbone.init
은 backbone network로부터 feature 뽑는 것
self.temporalconv
layer는 TAdaConv
layer로, 두번째 인자로 추출되는 feat
은 calibration weight, bias
정보를 포함
def init(self, xset):
xset = self.block1(xset)
xset = self.block2(xset)
xset = self.block3(xset)
xset=xset.unsqueeze(1)
xset,feat1 = self.temporalconv1.initset(xset)
xset = self.b_f1(xset)
xset=xset.unsqueeze(1)
xset,feat2 = self.temporalconv2.initset(xset)
xset = self.b_f2(xset)
return xset,feat1,feat2
tctrackplus_tracker.py
center_pos
기준으로 Instance_size
만큼 crop한 x_crop
이 실제 network inputx_crop
으로부터 bbox를 예측하고 원본 이미지에서 bbox를 다시 계산center_pose
및 size
를 업데이트def track(self, img,hp):
"""
args:
img(np.ndarray): BGR image
return:
bbox(list):[x, y, width, height]
"""
## -->
# img로 부터 x_crop 추출
###
...
x_crop = self.get_subwindow(img, self.center_pos,
cfg.TRACK.INSTANCE_SIZE,
round(s_x), self.channel_average)
##
# track inference
###
outputs = self.model.track(x_crop)
##
# 결과 추출 및 post-processing
###
...
cx = bbox[0] + self.center_pos[0]
cy = bbox[1] + self.center_pos[1]
...
##
# udpate state
###
self.center_pos = np.array([cx, cy])
self.size = np.array([width, height])
bbox = [cx - width / 2,
cy - height / 2,
width,
height]
best_score = score[best_idx]
return {
'bbox': bbox,
'best_score': best_score,
}
self.model.track()
→ model_builder.py
def track(self, x):
with t.no_grad():
xf,xfeat1,xfeat2 = self.backbone.eachtest(x,self.featset1,self.featset2)
loc,cls2,cls3,memory=self.grader(xf,self.zf,self.memory)
self.memory=memory
self.featset1=xfeat1
self.featset2=xfeat2
return {
'cls2': cls2,
'cls3': cls3,
'loc': loc
}
backbone으로부터 feature 추출
self.grader
로 output 추출
self.memory
, self.featureset
update
self.grader()
→ utile.py
(AT-Trans 부분인 듯)
def forward(self,x,z,ppres):
res3=self.conv2(self.xcorr_depthwise(x,z))
b,c,w,h=res3.size()
memory,res=self.transformer((res3).view(b,c,-1).permute(2, 0, 1),\
(ppres).view(b,c,-1).permute(2, 0, 1),\
res3.view(b,c,-1).permute(2, 0, 1))
res=res.permute(1,2,0).view(b,c,w,h)
loc=self.convloc(res)
acls=self.convcls(res)
cls1=self.cls1(acls)
cls2=self.cls2(acls)
return loc,cls1,cls2,memory
ppres
는 memory = temporal prior knowledge