android检测心率应用实例

Posted hemeiwolong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android检测心率应用实例相关的知识,希望对你有一定的参考价值。

参考博客:https://blog.csdn.net/qq_36982160/article/details/81260273

参考github:https://github.com/ZhaoYukai/HeartRate

如果运行时出现Program type already present: android.support.v4.app.BackStackRecord$Op错误,参考:https://stackoverflow.com/questions/49917614/program-type-already-present-android-support-v4-app-backstackrecordop

 

首先膜拜以上大神的博客和github,本人在引用上方github项目时出现了些问题,所以记下来以备以后用到。先讲下改错的过程:本人在Android Studio新建了项目后,就把github上的代码粘贴了过来,然后在manifests删掉以下内容:

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />

然后把github项目中的HeartRate-master\\HeartRate-master\\libs路径里的jar包复制到了AS模块里的libs路径下(后面看来android-support-v4.jar包用不到),选中后右键添加到库。然后在模块级的build.gradle中修改compileSdkVersion、targetSdkVersion为27(https://www.jianshu.com/p/808e1d127a33)。然后修改了两个implementation 如下:

implementation \'com.android.support:appcompat-v7:27.1.1\'
implementation \'com.android.support:support-v4:27.1.1\'

然后修改MainActivity的几个地方如下:

wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "DoNotDimScreen");  ====》

wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:wakeLock");

然后在运行app前授权允许使用照相机后即可运行app

运行效果图:

 

模块结构图:

 

模块级的build.gradle:

 1 apply plugin: \'com.android.application\'
 2 
 3 android {
 4     compileSdkVersion 27
 5 
 6 
 7 
 8     defaultConfig {
 9         applicationId "com.mingrisoft.heartdetect"
10         minSdkVersion 15
11         targetSdkVersion 27
12         versionCode 1
13         versionName "1.0"
14 
15         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 
17     }
18 
19     buildTypes {
20         release {
21             minifyEnabled false
22             proguardFiles getDefaultProguardFile(\'proguard-android.txt\'), \'proguard-rules.pro\'
23         }
24     }
25 
26 }
27 
28 dependencies {
29     implementation fileTree(include: [\'*.jar\'], dir: \'libs\')
30     implementation \'com.android.support:appcompat-v7:27.1.1\'
31     implementation \'com.android.support:support-v4:27.1.1\'
32     implementation \'com.android.support.constraint:constraint-layout:1.1.3\'
33     testImplementation \'junit:junit:4.12\'
34     androidTestImplementation \'com.android.support.test:runner:1.0.2\'
35     androidTestImplementation \'com.android.support.test.espresso:espresso-core:3.0.2\'
36     implementation files(\'libs/achartengine-1.0.0.jar\')
37 }

 

manifests:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.mingrisoft.heartdetect">
 4 
 5     <uses-permission android:name="android.permission.WAKE_LOCK" />
 6     <uses-permission android:name="android.permission.CAMERA" />
 7     <uses-feature android:name="android.hardware.camera" />
 8     <uses-feature android:name="android.hardware.camera.autofocus" />
 9 
10     <application
11         android:allowBackup="true"
12         android:icon="@mipmap/ic_launcher"
13         android:label="@string/app_name"
14         android:roundIcon="@mipmap/ic_launcher_round"
15         android:supportsRtl="true"
16         android:theme="@style/AppTheme">
17         <activity android:name=".MainActivity">
18             <intent-filter>
19                 <action android:name="android.intent.action.MAIN" />
20 
21                 <category android:name="android.intent.category.LAUNCHER" />
22             </intent-filter>
23         </activity>
24     </application>
25 
26 </manifest>

 

strings.xml:

1 <resources>
2     <string name="app_name">heartDetect</string>
3     <string name="hello_world">Hello world!</string>
4     <string name="action_settings">Settings</string>
5     <string name="show">显示</string>
6 
7 </resources>

 

activity_main.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context=".MainActivity">
 9 
10     <SurfaceView
11         android:id="@+id/id_preview"
12         android:layout_width="match_parent"
13         android:layout_height="200dp"
14         android:layout_marginLeft="50dp"
15         android:layout_marginRight="50dp" />
16 
17     <LinearLayout
18         android:id="@+id/id_linearLayout_graph"
19         android:layout_width="match_parent"
20         android:layout_height="200dp"
21         android:orientation="vertical" >
22     </LinearLayout>
23 
24     <TextView
25         android:id="@+id/id_tv_heart_rate"
26         android:layout_width="wrap_content"
27         android:layout_height="wrap_content"
28         android:layout_marginLeft="50dp"
29         android:layout_weight="1"
30         android:text="@string/show" >
31     </TextView>
32 
33     <TextView
34         android:id="@+id/id_tv_Avg_Pixel_Values"
35         android:layout_width="wrap_content"
36         android:layout_height="wrap_content"
37         android:layout_marginLeft="50dp"
38         android:layout_weight="1"
39         android:text="@string/show" >
40     </TextView>
41 
42     <TextView
43         android:id="@+id/id_tv_pulse"
44         android:layout_width="wrap_content"
45         android:layout_height="wrap_content"
46         android:layout_marginLeft="50dp"
47         android:layout_weight="1"
48         android:text="@string/show" >
49     </TextView>
50 
51 
52 </LinearLayout >

 

ImageProcessing:
 1 package com.mingrisoft.heartdetect;
 2 
 3 /**
 4  * 图像处理类
 5  */
 6 public abstract class ImageProcessing {
 7 
 8     /**
 9      * 内部调用的处理图片的方法
10      */
11     private static int decodeYUV420SPtoRedSum(byte[] yuv420sp , int width , int height) {
12         if (yuv420sp == null) {
13             return 0;
14         }
15 
16         final int frameSize = width * height;
17         int sum = 0;
18 
19         for (int j = 0 , yp = 0 ; j < height ; j++) {
20             int uvp = frameSize + (j >> 1) * width;
21             int u = 0;
22             int v = 0;
23             for (int i = 0 ; i < width ; i++, yp++) {
24                 int y = (0xff & ((int) yuv420sp[yp])) - 16;
25                 if (y < 0) {
26                     y = 0;
27                 }
28                 if ((i & 1) == 0) {
29                     v = (0xff & yuv420sp[uvp++]) - 128;
30                     u = (0xff & yuv420sp[uvp++]) - 128;
31                 }
32                 int y1192 = 1192 * y;
33                 int r = (y1192 + 1634 * v);
34                 int g = (y1192 - 833 * v - 400 * u);
35                 int b = (y1192 + 2066 * u);
36 
37                 if (r < 0) {
38                     r = 0;
39                 }
40                 else if (r > 262143) {
41                     r = 262143;
42                 }
43 
44                 if (g < 0) {
45                     g = 0;
46                 }
47                 else if (g > 262143) {
48                     g = 262143;
49                 }
50 
51                 if (b < 0) {
52                     b = 0;
53                 }
54                 else if (b > 262143) {
55                     b = 262143;
56                 }
57 
58                 int pixel = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
59                 int red = (pixel >> 16) & 0xff;
60                 sum += red;
61             }
62         }
63         return sum;
64     }
65 
66     /**
67      * 对外开放的图像处理方法
68      */
69     public static int decodeYUV420SPtoRedAvg(byte[] yuv420sp , int width , int height) {
70         if (yuv420sp == null) {
71             return 0;
72         }
73         final int frameSize = width * height;
74         int sum = decodeYUV420SPtoRedSum(yuv420sp, width, height);
75         return (sum / frameSize);
76     }
77 }

 

MainActivity:
  1 package com.mingrisoft.heartdetect;
  2 
  3 import android.app.Activity;
  4 import android.content.Context;
  5 import android.content.res.Configuration;
  6 import android.graphics.Color;
  7 import android.graphics.Paint.Align;
  8 import android.hardware.Camera;
  9 import android.hardware.Camera.PreviewCallback;
 10 import android.os.Bundle;
 11 import android.os.Handler;
 12 import android.os.Message;
 13 import android.os.PowerManager;
 14 import android.os.PowerManager.WakeLock;
 15 import android.util.Log;
 16 import android.view.SurfaceHolder;
 17 import android.view.SurfaceView;
 18 import android.view.ViewGroup.LayoutParams;
 19 import android.widget.LinearLayout;
 20 import android.widget.TextView;
 21 import android.widget.Toast;
 22 
 23 import org.achartengine.ChartFactory;
 24 import org.achartengine.GraphicalView;
 25 import org.achartengine.chart.PointStyle;
 26 import org.achartengine.model.XYMultipleSeriesDataset;
 27 import org.achartengine.model.XYSeries;
 28 import org.achartengine.renderer.XYMultipleSeriesRenderer;
 29 import org.achartengine.renderer.XYSeriesRenderer;
 30 
 31 import java.util.Timer;
 32 import java.util.TimerTask;
 33 import java.util.concurrent.atomic.AtomicBoolean;
 34 
 35 /**
 36  * 程序的主入口
 37  */
 38 public class MainActivity extends Activity {
 39     //曲线
 40     private Timer timer = new Timer();
 41     //Timer任务,与Timer配套使用
 42     private TimerTask task;
 43     private static int gx;
 44     private static int j;
 45 
 46     private static double flag = 1;
 47     private Handler handler;
 48     private String title = "pulse";
 49     private XYSeries series;
 50     private XYMultipleSeriesDataset mDataset;
 51     private GraphicalView chart;
 52     private XYMultipleSeriesRenderer renderer;
 53     private Context context;
 54     private int addX = -1;
 55     double addY;
 56     int[] xv = new int[300];
 57     int[] yv = new int[300];
 58     int[] hua=new int[]{9,10,11,12,13,14,13,12,11,10,9,8,7,6,7,8,9,10,11,10,10};
 59 
 60     private static final AtomicBoolean processing = new AtomicBoolean(false);
 61     //Android手机预览控件
 62     private static SurfaceView preview = null;
 63     //预览设置信息
 64     private static SurfaceHolder previewHolder = null;
 65     //Android手机相机句柄
 66     private static Camera camera = null;
 67     //private static View image = null;
 68     private static TextView mTV_Heart_Rate = null;
 69     private static TextView mTV_Avg_Pixel_Values = null;
 70     private static TextView mTV_pulse = null;
 71     private static WakeLock wakeLock = null;
 72     private static int averageIndex = 0;
 73     private static final int averageArraySize = 4;
 74     private static final int[] averageArray = new int[averageArraySize];
 75 
 76     /**
 77      * 类型枚举
 78      */
 79     public static enum TYPE {
 80         GREEN, RED
 81     };
 82 
 83     //设置默认类型
 84     private static TYPE currentType = TYPE.GREEN;
 85     //获取当前类型
 86     public static TYPE getCurrent() {
 87         return currentType;
 88     }
 89     //心跳下标值
 90     private static int beatsIndex = 0;
 91     //心跳数组的大小
 92     private static final int beatsArraySize = 3;
 93     //心跳数组
 94     private static final int[] beatsArray = new int[beatsArraySize];
 95     //心跳脉冲
 96     private static double beats = 0;
 97     //开始时间
 98     private static long startTime = 0;
 99 
100 
101 
102     @Override
103     public void onCreate(Bundle savedInstanceState) {
104         super.onCreate(savedInstanceState);
105         setContentView(R.layout.activity_main);  //这里注意要改成自己的布局文件
106 
107         initConfig();
108     }
109 
110     /**
111      * 初始化配置
112      */
113     @SuppressWarnings("deprecation")
114     private void initConfig() {
115         //曲线
116         context = getApplicationContext();
117 
118         //这里获得main界面上的布局,下面会把图表画在这个布局里面
119         LinearLayout layout = (LinearLayout)findViewById(R.id.id_linearLayout_graph);
120 
121         //这个类用来放置曲线上的所有点,是一个点的集合,根据这些点画出曲线
122         series = new XYSeries(title);
123 
124         //创建一个数据集的实例,这个数据集将被用来创建图表
125         mDataset = new XYMultipleSeriesDataset();
126 
127         //将点集添加到这个数据集中
128         mDataset.addSeries(series);
129 
130         //以下都是曲线的样式和属性等等的设置,renderer相当于一个用来给图表做渲染的句柄
131         int color = Color.GREEN;
132         PointStyle style = PointStyle.CIRCLE;
133         renderer = buildRenderer(color, style, true);
134 
135         //设置好图表的样式
136         setChartSettings(renderer, "X", "Y", 0, 300, 4, 16, Color.WHITE, Color.WHITE);
137 
138         //生成图表
139         chart = ChartFactory.getLineChartView(context, mDataset, renderer);
140 
141         //将图表添加到布局中去
142         layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
143 
144         //这里的Handler实例将配合下面的Timer实例,完成定时更新图表的功能
145         handler = new Handler() {
1

以上是关于android检测心率应用实例的主要内容,如果未能解决你的问题,请参考以下文章

基于STM32设计的实时心率检测仪

iOS 心率检测算法

使用 Google fit 从配对应用程序中读取 Wear os 手表的心率

ios检测心率[重复]

如何基于人体人脸跟踪实时监测心率?

Android:使用Tab检测单个片段viewpager