心跳数据采集及简单处理-黄
来源:互联网 发布:白城广逸网络地点 编辑:程序博客网 时间:2024/04/30 21:55
日期:2014年11月8日—2014年11月14日
1.本周已完成任务:心跳数据采集及简单处理
2.本周未完成任务:使用摄像头读出具体的心跳数
3.下周计划:使用FFT读出具体心跳
4.关键技术点说明:
由上一个博客里面的代码改编得来,基本上就是对读出来的波形进行了FIR滤波,滤除高频以及低频成分,以及一些简单的数据处理,获得幅度比较大的心跳信号。
FIR的参数使用MATLAB计算,采样率5Hz 带通0.6-1.5Hz,而函数是DSP直接抄过来的。
以下 是代码以及注释
package com.example.heart;import android.app.Activity;import android.content.pm.ActivityInfo;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.hardware.Camera;import android.hardware.Camera.PreviewCallback;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.DisplayMetrics;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.widget.TextView;public class MainActivity extends Activity {TextView heart_display;SurfaceView showDataSurfaceView=null;SurfaceHolder mSurfaceHolder=null;SurfaceView data_view=null;SurfaceHolder mdataviewHolder = null;int centerY;//中心线 int oldX=0; int oldY=200;//上一个XY 点 int newX=0; int newY=200; int currentX;//当前绘制到的X 轴上的点int ScreenWidth;int length=0;DisplayMetrics dm;private static String msg = "";int sigIn[] = null;//FIR输入数据int sigout[] = null;//FIR输出数据int FIR16_LPF_TEST[] = null;//FIR滤波系数,通过matlab计算获取int count = 0;private static Camera camera = null;private static SurfaceView preview = null;private static SurfaceHolder previewHolder = null; @SuppressWarnings("deprecation")@Override protected void onCreate(Bundle savedInstanceState) { super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); heart_display = (TextView)findViewById(R.id.textView2); preview = (SurfaceView)findViewById(R.id.preview);previewHolder = preview.getHolder();//获得SurfaceHolder对象previewHolder.addCallback(surfaceCallback);//添加回调函数previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); showDataSurfaceView=(SurfaceView)findViewById(R.id.showView); mSurfaceHolder=showDataSurfaceView.getHolder(); dm = new DisplayMetrics();//DisplayMetrics用来获取屏幕的分辨率,打点打到结束后返回0 getWindowManager().getDefaultDisplay().getMetrics(dm); ScreenWidth=dm.widthPixels;//屏幕的横向分辨率 sigIn = new int[128]; sigout = new int[128]; //FIR滤波系数 采样率5Hz 带通0.6-1.5HzFIR16_LPF_TEST = new int[] { 2304, 1589, -676, 1249, -501, -8175,-4413, 10240, 10240, -4413, -8175, -501, 1249, -676, 1589, 2304 }; data_view = (SurfaceView)findViewById(R.id.dataview);//数据处理后的数据显示 mdataviewHolder = data_view.getHolder(); // handler.post(runnable); } void drawline()//画线(点) { //获取Canvas,锁定画布 Canvas canvas = mSurfaceHolder.lockCanvas(new Rect(oldX, 0, newX,dm.heightPixels)); Paint mPaint=new Paint(); mPaint.setColor(Color.GREEN);//设定为绿色 mPaint.setStrokeWidth(1);//线宽为1像素 canvas.drawLine(oldX, oldY, newX, newY, mPaint);//Canvas绘画 oldX=newX; oldY=newY; mSurfaceHolder.unlockCanvasAndPost(canvas);//结束锁定画图,并提交改变,将图形显示 } //Handler handler = new Handler();//测试定时器,这个程序暂时用不到//Runnable runnable = new Runnable() {//@Override//public void run() {//heart_display.setText(String.valueOf("102"));//handler.postDelayed(runnable, 500);// 0.5秒刷新//}//}; int oldX1 = 0, oldY1 = 0;void drawline_fir()// 画线(点)用于显示数据{oldX1 = 0;Canvas canvas = mdataviewHolder.lockCanvas();canvas.drawColor(Color.BLACK);// 清除画布Paint mPaint = new Paint();mPaint.setColor(Color.RED);//设定为红色mPaint.setStrokeWidth(1);// 线宽为1像素int y;for (int i = 0; i < 128; i++) {y = sigout[i];canvas.drawLine(oldX1, oldY1, i, y, mPaint);// Canvas绘画oldX1 = i;oldY1 = y;}mdataviewHolder.unlockCanvasAndPost(canvas);// 结束锁定画图,并提交改变,将图形显示 } void ClearDraw() //清除画布 { Canvas canvas = mSurfaceHolder.lockCanvas(); canvas.drawColor(Color.BLACK);// 清除画布 mSurfaceHolder.unlockCanvasAndPost(canvas); } private Handler DrawHandler = new Handler() //画图Handler{public void handleMessage(Message m) {//画点drawline();currentX++;newX++;newY=Integer.valueOf(msg,10);//根据msg的值来确定当前的Y坐标Log.d("chenxuro", msg);if(newX==ScreenWidth-1)//当X坐标超过屏幕横向分辨率的时候清除屏幕,然后返回0{ClearDraw();currentX=0;oldX=0;newX=0;}}};private SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() //SurfaceView回调函数{ @Overridepublic void surfaceCreated(SurfaceHolder holder) {try {camera.setPreviewDisplay(previewHolder);//将camera连接到一个SurfaceView,准备实时预览camera.setPreviewCallback(previewCallback);//添加回调函数} catch (Throwable t) {Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t);}} @SuppressWarnings("deprecation")@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Camera.Parameters parameters = camera.getParameters();//获取camera界限parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);//打开闪光灯Camera.Size size = getSmallestPreviewSize(width, height, parameters);//得到最小尺寸预览if (size!=null) //设置预览大小{parameters.setPreviewSize(size.width, size.height);parameters.setPreviewFrameRate(5);//每秒5帧Log.d("parameters", "Using width="+size.width+" height="+size.height);}camera.setParameters(parameters);//设置camera界限camera.startPreview();//开始预览} @Overridepublic void surfaceDestroyed(SurfaceHolder holder) {//Ignore???//android.os.Process.killProcess(android.os.Process.myPid());}};private PreviewCallback previewCallback = new PreviewCallback() //摄像头回调{@Overridepublic void onPreviewFrame(byte[] data, Camera cam) //摄像头帧预览{if (data == null) throw new NullPointerException();Camera.Size size = cam.getParameters().getPreviewSize();if (size == null) throw new NullPointerException(); //关闭摄像头预览回调 camera.setPreviewCallback(null); int previewWidth=0; int previewHeight=0; if (data != null) //获取预览图片的信息 { previewWidth = camera.getParameters().getPreviewSize().width; previewHeight = camera.getParameters().getPreviewSize().height; } int CurrentRedSum=decodeYUV420SPtoRedSum(data, previewWidth, previewHeight); int CurrentRedAverage=CurrentRedSum/(previewWidth * previewHeight); if (count == 128)//数据滑窗count = 0;//获得红色部分数据,进行缩小处理防止溢出sigIn[count++] = CurrentRedSum*10/(previewWidth * previewHeight);//sigIn[count++] = CurrentRedAverage;fir(sigIn,FIR16_LPF_TEST,sigout);//调用FIR滤波函数drawline_fir();//显示滤波后的数据msg = String.valueOf(CurrentRedAverage);//获取红色部分平均的数据DrawHandler.sendEmptyMessage(0);//启动绘图 //打开摄像头预览回调 camera.setPreviewCallback(this); }};private static Camera.Size getSmallestPreviewSize(int width, int height, Camera.Parameters parameters) {Camera.Size result=null;for (Camera.Size size : parameters.getSupportedPreviewSizes()) {if (size.width<=width && size.height<=height) {if (result==null) {result=size;} else {int resultArea=result.width*result.height;int newArea=size.width*size.height;if (newArea<resultArea) result=size;}}}return result;}@Overridepublic void onResume() {super.onResume();camera = Camera.open();//打开摄像头camera.setDisplayOrientation(90);} @Overridepublic void onPause() {super.onPause();camera.setPreviewCallback(null);camera.stopPreview();//停止摄像头camera.release();camera = null;}//获得Red数据和private static int decodeYUV420SPtoRedSum(byte[] yuv420sp, int width, int height) {if (yuv420sp==null) return 0;final int frameSize = width * height;int sum = 0; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; int pixel = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); int red = (pixel >> 16) & 0xff; sum+=red; } } return sum;}//FIR滤波函数public static final short SIGNAL_LENGTH = 128;//数组长度public static final short FIR_ORDER = 16;//FIR阶数private static void fir(int x[], int h[], int y[]) {int i, j, nNow = 0;long sum;for (j = 0; j < SIGNAL_LENGTH; j++) {sum = 0;for (i = 0; i < FIR_ORDER; i++) {nNow = j - i;if (nNow < 0)nNow = SIGNAL_LENGTH + nNow;sum += (long) x[nNow] * h[i];}y[j] = (int) (sum >> 15);////幅度限制//if(y[j]>200)y[j]=200;//if(y[j]<0)y[j]=0;}}}
效果
0 0
- 心跳数据采集及简单处理-黄
- 数据采集与处理
- [C#]简单数据采集
- 数据采集及预处理
- php简单的数据采集
- 八爪鱼采集数据简单实例
- 关于MODIS数据说明及简单处理
- 利用Hadoop和Spark处理用户心跳周期数据
- 视频采集与处理-YUV数据
- matlab处理采集的声音数据
- node 数据采集-cookie处理,图片验证
- 物联网数据采集处理架构
- 图像采集及处理多线程编程
- 简单的网站数据采集程序(测试)
- 话单数据采集简单了解
- flume + Kafka采集数据 超简单
- windows音频PCM采集及简单编码
- 网络爬虫介绍及数据采集
- 谈谈C++私有继承
- 消息摘要算法-MAC算法系列
- [Leetcode]Jump Game && Jump Game II
- 琐碎事情
- jsoup:解析HTML用法小结
- 心跳数据采集及简单处理-黄
- cannot be used as a boolean
- HDU 1015 Safecracker 【DFS】
- 9个完整android开源app项目
- poj 2569 Etaoin Shrdlu 统计字符频率
- 危险代码:如何使用Unsafe操作内存中的Java类和对象—Part4
- 求平均成绩(杭电2023)(确实很水很繁琐)
- Thrift官方安装手册(译)
- .NET基础之迭代器