基于g-sensor的坐下的姿势识别。手机需要放在口袋里,手机拿在手上的暂时还不支持。
如果看不明白,可以先学习这篇文章
计步算法识别:http://blog.csdn.net/finnfu/article/details/45273183
算法流程:
1.五阶移动均值滤波
2.波谷峰值检测
3.根据波形特征判断是起立还是坐下
核心代码:
package com.research.sensor.finnfu.gesturedetector.detector;
import android.os.Environment;
import android.util.Log;
import com.research.sensor.finnfu.gesturedetector.MyApp;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Created by finnfu on 2017/6/3.
* 坐下
*/
public class SitDownDetector {
/*
* 五阶的均值滤波
* 第一阶是NUM1个数的均值
* 第二阶以第一阶的均值为输入,再进行NUM2个数的均值
* 第三阶以第二阶的均值为输入,再进行NUM2个数的均值
* 第四阶以第三阶的均值为输入,再进行NUM2个数的均值
* 第五阶以第四阶的均值为输入,再进行NUM2个数的均值
* */
public static final int NUM1 = 8;//取平均值的个数
public static final int NUM2 = 3;//取平均值的个数
float[] values1 = new float[NUM1];//一阶滤波,NUM1个值
float[] values2 = new float[NUM2];//二阶滤波,NUM2个值
float[] values3 = new float[NUM2];//三阶滤波,NUM2个值
float[] values4 = new float[NUM2];//四阶滤波,NUM2个值
float[] values5 = new float[NUM2];//五阶滤波,NUM2个值
int count1 = 0;
int count2 = 0;
int count3 = 0;
int count4 = 0;
int count5 = 0;
ArrayList keyValuelist = new ArrayList();//存放连续的波峰波谷值
public static final String KEY_NAME_VALUE = "value";
public static final String KEY_NAME_TIMEMILLIS = "timemillis";
public static final String KEY_NAME_TYPE = "type";//1代表波峰,-1代表波谷
//检测波谷相关
boolean isDirectionDecline = false;
int continueDeclineCount = 0;
int formerContinueDeclineCount = 0;
boolean formerDeclineStatus = false;
//检测波峰相关
boolean isDirectionUp = false;
int continueUpCount = 0;
int formerContinueUpCount = 0;
boolean formerUpStatus = false;
float ValleyPeakThread;
float ValleyThread;
int TimeIntervalOfValleyAndPeak = 350;
float mOldValue = 0;
public SitDownDetector(){
ValleyPeakThread = MyApp.getSitValleyPeakThread();
ValleyThread = MyApp.getSitValleyThread();
Log.i("Thread",""+"ValleyPeakThread: "+ValleyPeakThread +" "+"ValleyThread: "+ValleyThread);
}
//测试函数
public void testvalue(){
try {
String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath();
FileReader fileReader = new FileReader(rootPath+"/test.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String content = bufferedReader.readLine();
while (content!=null){
float v = Float.parseFloat(content);
inputValue(v);
content = bufferedReader.readLine();
}
fileReader.close();
bufferedReader.close();
}catch (IOException e){
e.printStackTrace();
}
}
public void inputValue(float v){
//第一次 NUM1个点的均值滤波
if(count1<NUM1){
values1[count1] = v;
if(count1 == NUM1-1){
averageValue1();
}
count1++;
}else{
translate1(v);
averageValue1();
}
}
//一阶滤波的均值
public void averageValue1(){
float v = 0;
for(int i = 0;i < NUM1;i++){
v += values1[i];
}
v = v/NUM1;
if(count2<NUM2){
values2[count2] = v;
if(count2 == NUM2-1){
averageValue2();
}
count2++;
}else{
translate2(v);
averageValue2();
}
}
//二阶滤波的均值
public void averageValue2(){
float v = 0;
for(int i = 0;i < NUM2;i++){
v += values2[i];
}
v = v/NUM2;
if(count3<NUM2){
values3[count3] = v;
if(count3 == NUM2-1){
averageValue3();
}
count3++;
}else{
translate3(v);
averageValue3();
}
}
//三阶滤波的均值
public void averageValue3(){
float v = 0;
for(int i = 0;i < NUM2;i++){
v += values3[i];
}
v = v/NUM2;
if(count4<NUM2){
values4[count4] = v;
if(count4 == NUM2-1){
averageValue4();
}
count4++;
}else{
translate4(v);
averageValue4();
}
}
//四阶滤波的均值
public void averageValue4(){
float v = 0;
for(int i = 0;i < NUM2;i++){
v += values4[i];
}
v = v/NUM2;
if(count5<NUM2){
values5[count5] = v;
if(count5 == NUM2-1){
averageValue5();
}
count5++;
}else{
translate5(v);
averageValue5();
}
}
//五阶滤波的均值
public void averageValue5(){
float v = 0;
for(int i = 0;i < NUM2;i++){
v += values5[i];
}
v = v/NUM2;
strategy(v);
}
public void strategy(float v){
Log.i("fushiqing",""+v);
if(keyValuelist.size() == 0){//监测第一个波谷点
if(mOldValue == 0){
mOldValue = v;
}else{
if(detectFirstValley(v,mOldValue)){
resetValleyRelativeParam();
}
mOldValue = v;
}
}else if(keyValuelist.size() == 1){//监测第二个波峰点
HashMap hashMap = (HashMap) keyValuelist.get(0);
if((int)hashMap.get(KEY_NAME_TYPE) == -1){
if(detectNormalPeak(v,mOldValue)){
resetPeakRelativeParam();
}
mOldValue = v;
}
}else if(keyValuelist.size() == 2){
judgeMaybeSitDown();
keyValuelist.clear();
resetPeakRelativeParam();
resetValleyRelativeParam();
mOldValue = v;
}
}
public boolean judgeMaybeSitDown(){
boolean result;
HashMap hashMap1 = (HashMap) keyValuelist.get(0);
HashMap hashMap2 = (HashMap) keyValuelist.get(1);
int type1 = (int)(int)hashMap1.get(KEY_NAME_TYPE);
int type2 = (int)hashMap2.get(KEY_NAME_TYPE);
if(type1 == -1 && type2 == 1){
long millis1 = (long)hashMap1.get(KEY_NAME_TIMEMILLIS);
float v1 = (float)hashMap1.get(KEY_NAME_VALUE);
float v2 = (float)hashMap2.get(KEY_NAME_VALUE);
float diffValue = v2 - v1;
long millis2 = (long)hashMap2.get(KEY_NAME_TIMEMILLIS);
if(millis2 - millis1 >= 320 && diffValue >= ValleyPeakThread && diffValue <= ValleyPeakThread+1){
Log.i("result","judgeMaybeSitDown");
result = true;
}else{
Log.i("result","judge sit down failed "+(millis2 - millis1)+" "+diffValue);
result = false;
}
}else{
Log.i("result","type wrong");
result = false;
}
return result;
}
/*
* 用于检测第一个波谷值,如果检测到符合要求的波谷值,则进行后续的检测
* 1.持续下降或持平大于等于4个点
* 2.波谷值小于8.2和7之间
* */
public boolean detectFirstValley(float newValue,float oldValue){
boolean result = false;
formerDeclineStatus = isDirectionDecline;
if(newValue < oldValue){
isDirectionDecline = true;
continueDeclineCount++;
}else{
formerContinueDeclineCount = continueDeclineCount;
continueDeclineCount = 0;
isDirectionDecline = false;
}
Log.i("process","formerContinueDeclineCount:"+formerContinueDeclineCount +" " +"oldValue:"+oldValue);
if(!isDirectionDecline && formerDeclineStatus
&& formerContinueDeclineCount >= 6 && oldValue<= ValleyThread+1.2 && oldValue>=ValleyThread){
long timeMillis = System.currentTimeMillis();
float valleyValue = oldValue;
HashMap hashMap = new HashMap();
hashMap.put(KEY_NAME_TIMEMILLIS,timeMillis);
hashMap.put(KEY_NAME_VALUE,valleyValue);
hashMap.put(KEY_NAME_TYPE,-1);
keyValuelist.add(hashMap);
Log.i("result","valleyValue"+valleyValue);
result = true;
}
return result;
}
/*
* 用于检测普通的符合要求的波峰
* */
public Boolean detectNormalPeak(float newValue,float oldValue){
Boolean result = false;
formerUpStatus = isDirectionUp;
if(newValue > oldValue){
isDirectionUp = true;
continueUpCount++;
}else{
isDirectionUp =false;
formerContinueUpCount = continueUpCount;
continueUpCount = 0;
}
if(!isDirectionUp && formerUpStatus){
long timeMillis = System.currentTimeMillis();
float peakValue = oldValue;
HashMap hashMap = new HashMap();
hashMap.put(KEY_NAME_TIMEMILLIS,timeMillis);
hashMap.put(KEY_NAME_VALUE,peakValue);
hashMap.put(KEY_NAME_TYPE,1);
keyValuelist.add(hashMap);
result = true;
}
return result;
}
public boolean detectNormalValley(float newValue,float oldValue){
boolean result = false;
formerDeclineStatus = isDirectionDecline;
if(newValue < oldValue){
isDirectionDecline = true;
continueDeclineCount++;
}else{
formerContinueDeclineCount = continueDeclineCount;
continueDeclineCount = 0;
isDirectionDecline = false;
}
if(!isDirectionDecline && formerDeclineStatus){
long timeMillis = System.currentTimeMillis();
float valleyValue = oldValue;
HashMap hashMap = new HashMap();
hashMap.put(KEY_NAME_TIMEMILLIS,timeMillis);
hashMap.put(KEY_NAME_VALUE,valleyValue);
hashMap.put(KEY_NAME_TYPE,-1);
keyValuelist.add(hashMap);
result = true;
}
return result;
}
//一阶滤波的平移
public void translate1(float v){
for(int i=1;i<NUM1;i++){
values1[i-1] = values1[i];
}
values1[NUM1-1] = v;
}
//二阶滤波的平移
public void translate2(float v){
for(int i=1;i<NUM2;i++){
values2[i-1] = values2[i];
}
values2[NUM2-1] = v;
}
//三阶滤波的平移
public void translate3(float v){
for(int i=1;i<NUM2;i++){
values3[i-1] = values3[i];
}
values3[NUM2-1] = v;
}
//四阶滤波的平移
public void translate4(float v){
for(int i=1;i<NUM2;i++){
values4[i-1] = values4[i];
}
values4[NUM2-1] = v;
}
//五阶滤波的平移
public void translate5(float v){
for(int i=1;i<NUM2;i++){
values5[i-1] = values5[i];
}
values5[NUM2-1] = v;
}
//初始化波谷监测的相关值
public void resetValleyRelativeParam(){
isDirectionDecline = false;
continueDeclineCount = 0;
formerContinueDeclineCount = 0;
formerDeclineStatus = false;
}
//初始化波峰监测的相关值
public void resetPeakRelativeParam(){
isDirectionUp = false;
continueUpCount = 0;
formerContinueUpCount = 0;
formerUpStatus = false;
}
}