6. Appendix2 : 동작인식 알고리즘 - GachonCapstoneHCI/pingpong_score GitHub Wiki

동작인식 시작하기

어떤 동작인식을 하느냐에 따라 다르고, 알고리즘도 많지만 여기서는 가장 기초적인 분석방법을 사용했다.
분석을 시작하는 방법은 다음과 같다.

1. Data Visualization : 데이터를 그래프로 그린다.

(1) SensorDashboard
SensorDashboard 에서 실시간으로 그려지는 데이터의 변화를 파악한다.

(2) Python Matplotlib
SensorDashoboard 또는 다른 프로그램을 통해서 추출된 데이터 파일(.dat, .txt 등)을 데스크탑에서 그래프를 그린다.

rawdata Python Matplotlib 으로 그린 데이터

import matplotlib.pyplot as plt
import numpy as np

moving_avg_size = 2

# 파일 읽기
f = open('input_file.txt', 'r')

lines = f.readlines()

# x y z가 들어가는 배열
x_axis_data = []
y_axis_data = []
z_axis_data = []

total_data = 0
count = len(lines)

# 마커 찍을 배열
markers_on = []
# 마커를 제외한 값들이 들어가있는 배열
filtered_lines = []

# 파일을 읽는다
for line in lines:
   # csv 파일을 분할한다
   data = line.split(',')

   #(0,0,0) 부분은 데이터가 아니라 태그이므로 값에서 제거한다
   if float(data[2].strip()) == 0. and float(data[3].strip()) == 0. and float(data[4].strip()) == 0.:
       # 가장 최근 값에 마킹한다
       filtered_lines[len(filtered_lines) - 1][0] = 1
   # 10이상인 값은 가속도 값이 아니므로 제외한다
   elif abs(float(data[2].strip())) > 10:
       pass
   # 수집되는 값
   else:
       tmp = [0, line]
       filtered_lines.append(tmp)

for i, line in enumerate(filtered_lines):
   print (i)
   # flag : 0이면 값, 1이면 태그
   flag = line[0]
   data = line[1].split(',')
   if flag == 1:
       markers_on.append(i)
       print("----------------flag : " + str(i))
   x_axis_data.append(float(data[2].strip()))
   y_axis_data.append(float(data[3].strip()))
   z_axis_data.append(float(data[4].strip()))
   print(data[2].strip() + " " + data[3].strip() + " " + data[4].strip())


# moving average
x_cumsum_vec = np.cumsum(np.insert(x_axis_data, 0, 0))
x_ma_vec = (x_cumsum_vec[moving_avg_size:] - x_cumsum_vec[:-moving_avg_size]) / moving_avg_size
y_cumsum_vec = np.cumsum(np.insert(y_axis_data, 0, 0))
y_ma_vec = (y_cumsum_vec[moving_avg_size:] - y_cumsum_vec[:-moving_avg_size]) / moving_avg_size
z_cumsum_vec = np.cumsum(np.insert(z_axis_data, 0, 0))
z_ma_vec = (z_cumsum_vec[moving_avg_size:] - z_cumsum_vec[:-moving_avg_size]) / moving_avg_size


# moving average 적용 X
#t = np.arange(0., len(filtered_lines), 1)

# moving average 적용 O
t = np.arange(0., len(x_ma_vec), 1)
f.close()

# moving average 적용 X
#plt.plot(t, x_axis_data, 'r-o', t, y_axis_data, 'b-o', t, z_axis_data, 'g-o',markersize=3)

# moving average 적용 O
plt.plot(t, x_ma_vec, 'r-o', t, y_ma_vec, 'b-o', t, z_ma_vec, 'g-o',markersize=3)

#draw graph
plt.show()
2. Data Analysis : 그래프의 변화를 관찰한 후, 어떤 특징이 있는지 파악한다.
이 프로젝트에서는 가만히 있을 때 Signal Vector Magnitude(x^2 + y^2 한 값)이 100 이상이 되는 경우가 없다는 것을 파악했다.

3. Data Preprocessing : 노이즈 데이터를 제거하고, 필터링을 한다
가속도 센서의 x,y,z 값을 분석했을 때, 간혹가다 100 ~ 1000 값이 나오는 경우가 있었다. 
일반적으로 가속도 센서 데이터는 -10 ~ 10 사이의 값을 가지기 때문에 이런 데이터(noise, outlier)들을 걸러주는 작업을 해야한다.
필요에 따라서 moving average, kalman filter 등 필터를 사용할 수 있다.
이 프로젝트 경우에는 특별한 필터를 사용하지 않았다.
이 프로젝트에서는 가속도 센서 x,y,z 값의 크기 변화를 보기위해서 Signal Vector Magnitude 를 사용했다.
이 때, z 값의 변화가 미미하고 오류를 발생시킨다고 간주하여 x^2 + y^2 으로만 계산했다.  

svm

4. Data Feature Extraction : 특징을 추출하기 위해 알고리즘을 개발한다.
데이터에서 특징을 추출하기 위한 방법은 어떤 특징을 추출하고 싶느냐에 따라 다르다.
이 프로젝트의 경우, 스윙 동작을 인식하기 위해서 Peak를 찾는 알고리즘을 사용했다.
알고리즘은 아래와 같다.
(1) 데이터가 일정 Threshold(ex.130) 이상이 될 경우에 Peak 로 간주한다.

threshold

(2) 그 이후에 들어오는 일정 window size(ex. 10) 를 두고, 이 window size 안에 있는 데이터에 대해서
일정 Threshold 이상인 데이터는 peak로 간주하지 않는다.
이 프로젝트에서 데이터를 분석한 결과 한 스윙에서 다음 스윙까지의 Interval은 항상 10 이상이었다. 
그렇기 때문에 첫 peak 발견 이후 10 개의 데이터에서 발생하는 peak 는 무시했다.

peakcluster

(3) 또한, 포핸드 스윙, 백핸드 스윙, 스윙이 아닌 행동을 구분하기 위해서 알고리즘을 보정할 수 있는 값을 썼다.
이 프로젝트에서는 중력 센서를 사용했다.
최종 결과

파이썬
중력센서 앱구현결과
사진 설명 : (왼쪽부터 오른쪽) 스윙에 따른 중력센서의 변화, 앱으로 구현한 Peak Detection 알고리즘, 스마트워치와 스마트폰 앱

⚠️ **GitHub.com Fallback** ⚠️