NIA ์์ด ๋ฐ์ดํฐ์ ์ ๊ฐ์ง๊ณ keypoint ๊ธฐ๋ฐ ์์ด ์ธ์ ๋ชจ๋ธ์ ๋ง๋๋ ํํ์ ์งํํ๋ค. ์ฐ์ ๋ด๊ฐ ๋งก์ ์ญํ์ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ + ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ์ด๋ค. ๋ชจ๋ธ๋ง์ ํ๊ธฐ ์ , ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ ๋งก์ ๊ฒ์ด๋ค..
์ฒ์์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์ ๋ชจ๋ฅด๊ณ , ์ผ๋จ ๋์๊ฐ๊ฒ์ ์ง์คํ๋ค๊ฐ,
์ค๊ฐ๋ฐํ ์ดํ์๋ ์ง์ง ๊ด์ฐฎ์ ์ ์ฒ๋ฆฌ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๊ตฌ์กฐ๋ฅผ ์์ ํ ์๋ดค๋ค.
์ฒ์์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ด๋ ๊ฒ ์ดํดํ๋ค.
WORD0001~0160 ร REAL01~05 ร F ๋ฒ์
๊ทธ๋์ ์ค์ REAL์ด 16๊ฐ๋ผ๋ ๊ฑธ ๋ชจ๋ฅด๊ณ ,
REAL 01~05๋ง ๋์์ผ๋ก keypoint๋ฅผ ์ถ์ถํ๋ค.
for z in "$SRC"/*.zip; do
for i in $(seq -f "%04g" 1 160); do
unzip -qq "$z" "*/NIA_SL_WORD${i}_REAL0[1-5]_F*" -d "$DST"
done
done
์ง๊ธ ์์ ๋ณด๋ฉด,
๋ฐ์ดํฐ 16๊ฐ์ธ ์ค ๋ชจ๋ฅด๊ณ 5๊ฐ๋ง ์ฐ๋ฉด์ ๋ฐ์ดํฐ๊ฐ ๋๋ฌด ์ ๋ค๊ณ ๊ณ ๋ฏผํ๊ณ ์์๋ ์๊ธฐ์๋ค.
REAL์ด 5๊ฐ๋ผ๊ณ ์๊ฐํ๋๊น, ๋จ์ด๋ณ ์ํ ์๊ฐ ๋น์ฐํ ๋งค์ฐ ์ ์ด ๋ณด์๋ค.
๊ทธ๋์ ์ด๋๋ ์ ์ฒ๋ฆฌ ์ ๋ต์ ํฌ์ปค์ค๊ฐ
โ๋ฐ์ดํฐ๊ฐ ์ ์ผ๋ โ ์ด๋ป๊ฒ๋ ๋ฐ์ดํฐ๋ฅผ ๋๋ฆฌ์(์ฆ๊ฐ)โ
์ ๋ง์ถฐ์ ธ ์์๋ค.
์ง๊ธ ์๊ฐํด๋ณด๋ฉด,
๋ฐ์ดํฐ๊ฐ ์ ๋ค โ ์ฆ๊ฐ! ์ด๋ผ๋ ์๊ฐ ์์ฒด๋ ๋์์ง ์์์ง๋ง,
๊ทธ ์ ์ ๋ฐ์ดํฐ๊ฐ ๋ช๊ฐ์ธ์ง๋ถํฐ ์ ํ์ธํ์์ด์ผ ํ๋ค.
1์ฐจ ๋ฒ์ ์์ ๋ ํ๋ ํ๋ ์ ํ์ด StandardScaler์๋ค.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train.reshape(-1, X_train.shape[-1]))
X_train_scaled = X_train_scaled.reshape(X_train.shape)
๋น์์๋:
๋ฅ๋ฌ๋ ์ ์ feature scaling์ ๊ธฐ๋ณธ์ด๋ผ๋ ์๊ฐ์ผ๋ก,
์ขํ ๊ฐ ์ ์ฒด๋ฅผ ํ๊ท 0, ๋ถ์ฐ 1๋ก ๋ง์ถ๋ StandardScaler๋ฅผ ์ ์ฉํ๋ค.
๊ทผ๋ฐ skeleton ์ขํ์ StandardScaler๋ฅผ ์ฐ๋ฉด ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
๊ฐ joint์ ์๋์ ์ธ ์์น ์ ๋ณด๊ฐ ์๊ณก๋์๋ค.
๋, (x,y)์ โ๊ฑฐ๋ฆฌ ๊ตฌ์กฐโ๊ฐ ํํธ๋ฌ์ ธ์, Mid-Hip ๊ธฐ์ค ๊ฑฐ๋ฆฌ, ์ํ/์ข์ฐ ๊ด๊ณ๊ฐ ๊นจ์ ธ๋ฒ๋ ธ๋ค.
1์ฐจ ๋ฒ์ ์์๋ ์ด๊ฑธ ํฌ๊ฒ ์ธ์งํ์ง ๋ชปํ๊ณ , โ์์น๊ฐ ์ ์ ๊ทํ๋์๋คโ ์ ๋๋ก๋ง ๋ณด๊ณ ๋์ด๊ฐ๋ค.
์ ๋ฆฌํด๋ณด๋ฉด, REAL=5๋ผ๊ณ ๋ฏฟ๋ ์์ ์ ์ ์ฒ๋ฆฌ๋ ์ด๋ฐ ๋๋์ด์๋ค.
์ด ์ํ๋ก๋ ์ผ๋จ ๋์๊ฐ๋ ๋ชจ๋ธ์ ๋ง๋ค ์ ์์ง๋ง,
๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ๋๋ก ์ดํดํ๊ณ ์ฐ๋ ์์ค์ ์๋์๋ค.
์ค๊ฐ ๋ฐํ์์ ๋์๋ ๊ต์๋์ ํต์ฌ ํผ๋๋ฐฑ:
์ด๊ฑธ ๊ณ๊ธฐ๋ก ์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ์ฒ์๋ถํฐ ๋ค์ ์งฐ๋ค.
๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ค์ ๋ณด๋, ์๊ณ ๋ณด๋ REAL์ 5๊ฐ๊ฐ ์๋๋ผ 16๊ฐ์๋ค.
5๊ฐ์ฒ๋ผ ๋ณด์๋ ๊ฑด โ์ดฌ์ ๊ฐ๋โ์๊ณ , ๊ทธ ์๋์ ์ค์ ์ดฌ์๋ณธ REAL01~REAL16์ด ์กด์ฌํ๋ค.
์ด๊ฑธ ๋ค๋ฆ๊ฒ ์ดํดํด์ zip ํ์ผ์ ์ ๋ถ ๋ค์ ๋ค์ด๋ก๋ํ๊ณ , ํจํด์ ๋ค์ ์ก์ ์ ์ฒด 160 ร 16 ร F ๋ฒ์ ์ ์ ํํ ์ถ์ถํ๋ ์์ ์ ๋ค์ ํ๋ค.

๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋งค์นญํ๋๋ฐ๋ง 10์๊ฐ์ ๋ ๊ฑธ๋ ธ๋ค.. ใ ใ
keypoint(frame๋ณ ์ขํ๊ฐ์ ๋ด๊ณ ์๋ jsonํ์ผ)์ morpheme(์์ด์์ ์์๊ณผ ๋์ ์๊ฐ & ๋จ์ด์๋ฏธ๋ฅผ ๋ด๊ณ ์๋ json ํ์ผ)๋ฅผ ์์ ํ๊ฒ ๋งค์นญํ๊ธฐ ์ํด
fast_index๋ฅผ ๋ค์ ๋ง๋ค์๋ค.
word_id = filename.split("_")[2].replace("WORD", "")
real_id = filename.split("_")[3].replace("REAL", "")
key = f"{word_id}_{real_id}"
fast_index[key] = {
"keypoint": keypoint_path,
"morpheme": morpheme_path
}
ํ์ผ์ด๋ฆ์ ๊ธฐ์ค์ผ๋ก WORD / REAL ๊ธฐ์ค์ผ๋ก ์ ํํ ๋งค์นญ์ ํ์๊ณ , ์ค์ ๋ก 1757๊ฐ segment๋ฅผ ์์ ์ ์ผ๋ก ํ๋ณดํ๋ค.
keypoint_data_list = [item["frames"] for item in data_json]
padded_data = pad_sequences(
keypoint_data_list,
padding='post',
dtype='float32'
)
raw_data = np.array(padded_data) # (N, T, 137, 3)
๋ชจ๋ sequence๋ฅผ ๊ฐ์ ๊ธธ์ด T๋ก ๋ง์ถ์๋ค.
๊ฐ ํ๋ ์๋ง๋ค 137๊ฐ keypoint ร (x, y, conf) ๊ตฌ์กฐ๋ก ํ์
๋์๋ค.
์ด๋๋ถํฐ๋ Mid-Hip ๊ธฐ์ค ์๋์ขํ๋ฅผ ์ ๋๋ก ์ ์ฉํ๋ค.
def apply_midhip_relative(raw):
N, T, F = raw.shape
num_points = F // 3
arr = raw.reshape(N, T, num_points, 3)
REF = 0 # Mid-Hip
ref_xy = arr[:, :, REF, :2] # (N, T, 2)
ref_xy = ref_xy[:, :, None, :] # (N, T, 1, 2)
arr[:, :, :, :2] -= ref_xy # x,y๋ง ์๋์ขํ ๋ณํ
return arr.reshape(N, T, F)
์ค์ํ ์ :
์ด์ ๋ฒ์ ๊ณผ ๋ฌ๋ฆฌ, confidence๋ ๊ฑด๋๋ฆฌ์ง ์์๋ค. (x์ y์ conf ํท๊ฐ๋ฆฌ์ง๋ง์!!)
(x, y)๋ง Mid-Hip์ ๊ธฐ์ค์ผ๋ก ์ด๋์์ผฐ๋ค.
๊ต์๋ ํผ๋๋ฐฑ ์ค ํ๋๊ฐ:
๋ฐ์ดํฐ์ ๋นํด input ์ฐจ์์ด ๋๋ฌด ํฌ๋ค.
์๋ค. ๊ทธ๋์ 137๊ฐ ์ ์ฒด keypoint๋ฅผ ์ฐ๋ ๋์ ,
์๋ฏธ ์๋ ์ผ๋ถ๋ง ๋ฝ๋ ์ ๋ต์ผ๋ก ๊ฐ๋ค.
POSE_IDXS = [0,1,2,3,4,5,6,7]
HAND_IDXS = [4,8,12,16,20]
def select_keypoints(frame_137x3):
pose = frame_137x3[:25]
lh = frame_137x3[25:46]
rh = frame_137x3[46:67]
selected = []
for idx in POSE_IDXS: selected.append(pose[idx])
for idx in HAND_IDXS: selected.append(lh[idx])
for idx in HAND_IDXS: selected.append(rh[idx])
return np.array(selected).reshape(-1) # 18 ร (x,y,conf) = 54
์ด๋ ๊ฒ ํด์:
์์ฒด + ์์์ ํต์ฌ ํฌ์ธํธ๋ง ์ฌ์ฉํ๋ค.
์ฐจ์ ์๋ฅผ ํ ์ค์ด๋ฉด์, ์๋ฏธ ์๋ ๊ด์ ์ ๋ณด๋ ์ ์งํ๋ ์ต์์ ๋ฐฉ๋ฒ์ด์๋ค.
๋ฐ์ดํฐ๋ฅผ ์์ธํ ๊น๋ณด๋,
confidence๊ฐ 0์ธ ๊ฐ์ด ์ ์ฒด์ ๊ฑฐ์ ์ ๋ฐ์ด์๋ค.
์ฐจ์์ ์ถ์ํ๋ค๋ณด๋, ์์ด ๊ฐ๋ ค์ง frame๋ค์ด ๋ง์๊ณ , confidence๊ฐ์ด 0์ธ frame๋ค์ด ์ฐ์์ผ๋ก ๋์ค๋ ๊ฒฝ์ฐ, ๋จ์ง interpolation์ผ๋ก๋ ๋ณด๊ฐ์ด ๋ถ๊ฐํ๋ค.
3๋จ๊ณ๋ก ์ค๊ณํ๋ค.
(1) forward-fill
for t in range(1, T):
if conf[t] < th and conf[t-1] >= th:
x[t] = x[t-1]
y[t] = y[t-1]
conf[t] = conf[t-1]
๋ฐ๋ก ์ด์ ํ๋ ์์ด ์ ๋ขฐ ๋์ผ๋ฉด โ ๊ทธ ๊ฐ์ ํ์ฌ 0 ์์น์ ๋ณต์ฌ
(2) backward-fill
for t in range(T-2, -1, -1):
if conf[t] < th and conf[t+1] >= th:
x[t] = x[t+1]
y[t] = y[t+1]
conf[t] = conf[t+1]
๋ค์์๋ถํฐ ์ค์บํ๋ฉด์, ๋ค์ valid ๊ฐ์ด ์์ผ๋ฉด ์์ชฝ ๋น ์นธ์ ์ฑ์
(3) ๊ตฌ๊ฐ ๋จ์ ์ ํ ๋ณด๊ฐ
for s, e in zip(seg_starts, seg_ends):
prev_t = s - 1
next_t = e + 1
if prev_t < 0 or next_t >= T:
continue
for t in range(s, e+1):
ratio = (t - s + 1) / (e - s + 2)
x[t] = (1-ratio) * x[prev_t] + ratio * x[next_t]
y[t] = (1-ratio) * y[prev_t] + ratio * y[next_t]
conf[t] = max(conf[prev_t], conf[next_t])
์ฐ์ zero ๊ตฌ๊ฐ ์ ์ฒด๋ฅผ ์/๋ค ํ๋ ์์ผ๋ก ๋ถ๋๋ฝ๊ฒ ์ฑ์, ์์ด ์ ๊น ์ฌ๋ผ์ก์ด๋ trajectory๊ฐ ๋๊ธฐ์ง ์๊ฒ ๋ง๋ค์ด์ค
์ด ๊ณผ์ ์ ๊ฑฐ์น๊ณ ๋์,
confidence ์ต์๊ฐ: 1.0
์ต๋๊ฐ: 1.0
0์ธ ๊ฐ ๋น์จ: 0%
์ฆ,
confidence ๊ตฌ๋ฉ(0) ๋ฌธ์ ๋ ์์ ํ ํด๊ฒฐํ๋ค.
๋ณด๊ฐ๊น์ง ๋๋ ํ, ์ต์ข ์ ์ผ๋ก๋ confidence๋ฅผ ์ ๋ ฅ์์ ์์ ์ ๊ฑฐํ๋ค.
def remove_confidence(X):
N,T,F = X.shape
P = F//3
coords = X.reshape(N,T,P,3)[:,:,:,:2] # x,y๋ง
return coords.reshape(N,T,P*2) # 36์ฐจ์
๊ทธ๋ฆฌ๊ณ ๊ฐ์ด ๋๋ฌด ํฌ์ง ์๋๋ก 1000์ผ๋ก ๋๋์๋ค.
X_xy /= 1000.0
๊ฒ์ฆ ๊ฒฐ๊ณผ:
์ต์ข
x,y ๋ฒ์: ์ฝ [-1.01 ~ +1.30]
3-sigma ๊ธฐ์ค ์ด์์น ๋น์จ: 0.0024% (๊ฑฐ์ ์์)
์ฒ์์๋ โREAL์ด 5๊ฐ์ธ ์ค ์์๋ ์์ ์ ์ ์ฒ๋ฆฌโ๊ฐ ์์๊ณ ,
๊ทธ ์์ ์ฆ๊ฐ๊ณผ StandardScaler๋ฅผ ์ฌ๋ ค์ ์ด๋ป๊ฒ๋ ๋์๊ฐ๋ ๋ชจ๋ธ์ ๋ง๋ค๋ ค๊ณ ํ๋ค.
์ค๊ฐ๋ฐํ ์ดํ์๋:
๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ์ดํดํ๊ณ , keypoint ํ์ง๊ณผ confidence๋ฅผ ์ฑ๊ธฐ๊ณ , Mid-Hip, ํต์ฌ keypoint ์ ํ, ๋ณด๊ฐ, ์ค์ผ์ผ๋ง๊น์ง ํ๋์ฉ ๋ ผ๋ฆฌ์ ์ผ๋ก ์์ ์ฌ๋ฆฌ๋ฉด์ ์ง๊ธ์ ์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ v2๋ฅผ ์์ฑํ๋ค.
๋ฐ์ดํฐ๋ฅผ ์ ์ฒ๋ฆฌํ๋๊ฒ๋ ๋งค์ฐ ์ค์ํ์ง๋ง, ๋ฐ์ดํฐ ์๊ฐ ๋ง์ ๋๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋จผ์ ํ์ ํ๋ ๊ฒ์ด ์ค์ํ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.