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.pycenter_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.pydef 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