Project/DTW

여러 비디오를 dtw를 통해 타임시퀀스 맞추기

황공진 2022. 10. 13. 14:36

우선 미디어파이프를 통해 여러 영상을 돌리면서 각 관절 데이터를 저장
저장은 x[video][frame][joint], y[video][frame][joint]의 형태로 저장했으며
x[1][30][2]는 두번째 영상의 31번째 프레임의 2번관절에 대한 x축 좌표가 저장되어있다.

def angle_of_vectors(vec1,vec2):
    a,b,c,d=vec1[0],vec1[1],vec2[0],vec2[1]
    dotProduct = a*c + b*d
    modOfVector1 = math.sqrt( a*a + b*b)*math.sqrt(c*c + d*d) 
    angle = dotProduct/modOfVector1
    angleInDegree = math.degrees(math.acos(angle))
    return angleInDegree

# 12-11 어깨, 12-24 왼옆구리, 11-23 오른옆구리, 24-23 허리, 24-26 왼허벅 23-25 오른허벅
# 26-28 왼종아리, 25-27 오른종아리, 28-32 왼발등, 27-31 오른발등
# 12-14 왼팔, 11-13 오른팔, 14-16 왼전완, 13-15 오른전완
matchIndex=[[12,11],[12,24],[11,23],[24,23],[24,26],[23,25],[26,28],[25,27],[28,32],[27,31],
           [12,14],[11,13],[14,16],[13,15]]

# x[0][0~f][djRo]
# x[1][0~f][djRo]

#x[video][frame][angle]
#angle = [[[a1...a14], frame], ... video]
angle = [[], [], [], [], [], [], []]

for i in range(videoNum):
    for frameNum in range(videoEachFrame[i]):
        temp = []
        for idx in range(len(matchIndex)):
            temp.append(angle_of_vectors([x[i][frameNum][matchIndex[idx][0]],y[i][frameNum][matchIndex[idx][0]]],[x[i][frameNum][matchIndex[idx][1]],y[i][frameNum][matchIndex[idx][1]]]))
        angle[i].append(temp)

저장된 데이터를 관절끼리 묶어서(12번-11번 관절이면 어깨)
관절들의 각도를 계산하여 다시 저장해두었다 (만약 서있는 위치가 다르면 좌표로 할 경우 다른 자세라고 판단)
(하지만, 각도로 한다면 같은 자세로 다른 위치에 서있더라도 같은 자세라고 판단하고 dtw matching이 잘 될것)

이를 dtw에 적용시켜서 나오는 table을 저장했으며 (관절 묶은 데이터가 14개라 14번)
14개의 테이블을 평균을 구하여 다시 dtw path를 출력하였다.

while i>0 or j>0:
    a= totalCostMap[i-1,j-1]
    b= totalCostMap[i,j-1]
    c= totalCostMap[i-1,j]
    if min(a,b,c)==a:
        i=i-1
        j=j-1
    elif min(a,b,c)==b:
        j=j-1
    elif min(a,b,c)==c:
        i=i-1
    path.append((i,j))
path.reverse()

원래라면 2d data에 대해 dtw를 수행하지만
관절 데이터 14개를 묶어서 한 번에 dtw를 수행할 수 있도록 하여 차원이 하나 더 늘어난 데이터에 대해 처리를 한 것이다.
왜 이렇게 하였는가.
만약 팔에 대해, 다리에 대해, .... 따로 dtw를 시도한다면
팔은 두 영상에 대해 1-3 frame matching,  다리는 1-10 frame matching이라면,
첫 프레임이 어떤 프레임과 매칭된다고 판단하기 힘들것이다.
우리는 차원을 늘려 팔,다리 등등 모든 데이터에 대해 수행하기에 그런 일이 없다.
매칭된 path를 통해 두 영상에서 잘 매칭되었나 확인하기 위해 해당 프레임의 영상 데이터를 뽑아봤다.

for i in range(1,3):
    video = "../video/front%d.mp4" % (i) 
    cap = cv2.VideoCapture(video)
    frame=0
    while cap.isOpened():
        success, image = cap.read()
        if not success:
            break
        for j in range(len(path)):
            if i==1 and (frame == path[j][0]):
                cv2.imwrite("../image/%d[1].jpg" % (j), image) 
                break
            elif i==2 and (frame == path[j][1]):
                cv2.imwrite("../image/%d[2].jpg" % (j), image) 
                break
        frame+=1
    cap.release()

서로 다른 영상이지만 매칭된 프레임데이터를 보면 아주 비슷한 자세를 취하고 있는 것을 확인할 수 있다.
또한 좌표데이터가 아닌 앵글데이터를 사용했기에 서있는 좌표에 다르더라도 잘 매칭이 되고 있다.


전체 코드
[비공개처리]