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检测心率应用实例的主要内容,如果未能解决你的问题,请参考以下文章