zoukankan      html  css  js  c++  java
  • 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-masterHeartRate-masterlibs路径里的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() {
    146             @Override
    147             public void handleMessage(Message msg) {
    148                 //刷新图表
    149                 updateChart();
    150                 super.handleMessage(msg);
    151             }
    152         };
    153 
    154         task = new TimerTask() {
    155             @Override
    156             public void run() {
    157                 Message message = new Message();
    158                 message.what = 1;
    159                 handler.sendMessage(message);
    160             }
    161         };
    162 
    163         timer.schedule(task, 1,20);           //曲线
    164         //获取SurfaceView控件
    165         preview = (SurfaceView) findViewById(R.id.id_preview);
    166         previewHolder = preview.getHolder();
    167         previewHolder.addCallback(surfaceCallback);
    168         previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    169 
    170         mTV_Heart_Rate = (TextView) findViewById(R.id.id_tv_heart_rate);
    171         mTV_Avg_Pixel_Values = (TextView) findViewById(R.id.id_tv_Avg_Pixel_Values);
    172         mTV_pulse = (TextView) findViewById(R.id.id_tv_pulse);
    173 
    174         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    175         wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:wakeLock");
    176     }
    177 
    178     //    曲线
    179     @Override
    180     public void onDestroy() {
    181         //当结束程序时关掉Timer
    182         timer.cancel();
    183         super.onDestroy();
    184     };
    185 
    186     /**
    187      * 创建图表
    188      */
    189     protected XYMultipleSeriesRenderer buildRenderer(int color, PointStyle style, boolean fill) {
    190         XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
    191 
    192         //设置图表中曲线本身的样式,包括颜色、点的大小以及线的粗细等
    193         XYSeriesRenderer r = new XYSeriesRenderer();
    194         r.setColor(Color.RED);
    195         r.setLineWidth(1);
    196         renderer.addSeriesRenderer(r);
    197         return renderer;
    198     }
    199 
    200     /**
    201      * 设置图标的样式
    202      * @param renderer
    203      * @param xTitle:x标题
    204      * @param yTitle:y标题
    205      * @param xMin:x最小长度
    206      * @param xMax:x最大长度
    207      * @param yMin:y最小长度
    208      * @param yMax:y最大长度
    209      * @param axesColor:颜色
    210      * @param labelsColor:标签
    211      */
    212     protected void setChartSettings(XYMultipleSeriesRenderer renderer, String xTitle, String yTitle,
    213                                     double xMin, double xMax, double yMin, double yMax, int axesColor, int labelsColor) {
    214         //有关对图表的渲染可参看api文档
    215         renderer.setChartTitle(title);
    216         renderer.setXTitle(xTitle);
    217         renderer.setYTitle(yTitle);
    218         renderer.setXAxisMin(xMin);
    219         renderer.setXAxisMax(xMax);
    220         renderer.setYAxisMin(yMin);
    221         renderer.setYAxisMax(yMax);
    222         renderer.setAxesColor(axesColor);
    223         renderer.setLabelsColor(labelsColor);
    224         renderer.setShowGrid(true);
    225         renderer.setGridColor(Color.GREEN);
    226         renderer.setXLabels(20);
    227         renderer.setYLabels(10);
    228         renderer.setXTitle("Time");
    229         renderer.setYTitle("mmHg");
    230         renderer.setYLabelsAlign(Align.RIGHT);
    231         renderer.setPointSize((float) 3 );
    232         renderer.setShowLegend(false);
    233     }
    234 
    235     /**
    236      * 更新图标信息
    237      */
    238     private void updateChart() {
    239         //设置好下一个需要增加的节点
    240         if(flag == 1) {
    241             addY = 10;
    242         }
    243         else {
    244             flag = 1;
    245             if(gx < 200){
    246                 if(hua[20] > 1){
    247                     Toast.makeText(MainActivity.this, "请用您的指尖盖住摄像头镜头!", Toast.LENGTH_SHORT).show();
    248                     hua[20] = 0;
    249                 }
    250                 hua[20]++;
    251                 return;
    252             }
    253             else {
    254                 hua[20] = 10;
    255             }
    256             j = 0;
    257         }
    258         if(j < 20){
    259             addY=hua[j];
    260             j++;
    261         }
    262 
    263         //移除数据集中旧的点集
    264         mDataset.removeSeries(series);
    265 
    266         //判断当前点集中到底有多少点,因为屏幕总共只能容纳100个,所以当点数超过100时,长度永远是100
    267         int length = series.getItemCount();
    268         int bz = 0;
    269         //addX = length;
    270         if (length > 300) {
    271             length = 300;
    272             bz=1;
    273         }
    274         addX = length;
    275         //将旧的点集中x和y的数值取出来放入backup中,并且将x的值加1,造成曲线向右平移的效果
    276         for (int i = 0; i < length; i++) {
    277             xv[i] = (int) series.getX(i) - bz;
    278             yv[i] = (int) series.getY(i);
    279         }
    280 
    281         //点集先清空,为了做成新的点集而准备
    282         series.clear();
    283         mDataset.addSeries(series);
    284         //将新产生的点首先加入到点集中,然后在循环体中将坐标变换后的一系列点都重新加入到点集中
    285         //这里可以试验一下把顺序颠倒过来是什么效果,即先运行循环体,再添加新产生的点
    286         series.add(addX, addY);
    287         for (int k = 0; k < length; k++) {
    288             series.add(xv[k], yv[k]);
    289         }
    290         //在数据集中添加新的点集
    291         //mDataset.addSeries(series);
    292 
    293         //视图更新,没有这一步,曲线不会呈现动态
    294         //如果在非UI主线程中,需要调用postInvalidate(),具体参考api
    295         chart.invalidate();
    296     } //曲线
    297 
    298 
    299     @Override
    300     public void onConfigurationChanged(Configuration newConfig) {
    301         super.onConfigurationChanged(newConfig);
    302     }
    303 
    304     @Override
    305     public void onResume() {
    306         super.onResume();
    307         wakeLock.acquire();
    308         camera = Camera.open();
    309         startTime = System.currentTimeMillis();
    310     }
    311 
    312     @Override
    313     public void onPause() {
    314         super.onPause();
    315         wakeLock.release();
    316         camera.setPreviewCallback(null);
    317         camera.stopPreview();
    318         camera.release();
    319         camera = null;
    320     }
    321 
    322 
    323     /**
    324      * 相机预览方法
    325      * 这个方法中实现动态更新界面UI的功能,
    326      * 通过获取手机摄像头的参数来实时动态计算平均像素值、脉冲数,从而实时动态计算心率值。
    327      */
    328     private static PreviewCallback previewCallback = new PreviewCallback() {
    329         public void onPreviewFrame(byte[] data, Camera cam) {
    330             if (data == null) {
    331                 throw new NullPointerException();
    332             }
    333             Camera.Size size = cam.getParameters().getPreviewSize();
    334             if (size == null) {
    335                 throw new NullPointerException();
    336             }
    337             if (!processing.compareAndSet(false, true)) {
    338                 return;
    339             }
    340             int width = size.width;
    341             int height = size.height;
    342 
    343             //图像处理
    344             int imgAvg = ImageProcessing.decodeYUV420SPtoRedAvg(data.clone(),height,width);
    345             gx = imgAvg;
    346             mTV_Avg_Pixel_Values.setText("平均像素值是" + String.valueOf(imgAvg));
    347 
    348             if (imgAvg == 0 || imgAvg == 255) {
    349                 processing.set(false);
    350                 return;
    351             }
    352             //计算平均值
    353             int averageArrayAvg = 0;
    354             int averageArrayCnt = 0;
    355             for (int i = 0; i < averageArray.length; i++) {
    356                 if (averageArray[i] > 0) {
    357                     averageArrayAvg += averageArray[i];
    358                     averageArrayCnt++;
    359                 }
    360             }
    361 
    362             //计算平均值
    363             int rollingAverage = (averageArrayCnt > 0)?(averageArrayAvg/averageArrayCnt):0;
    364             TYPE newType = currentType;
    365             if (imgAvg < rollingAverage) {
    366                 newType = TYPE.RED;
    367                 if (newType != currentType) {
    368                     beats++;
    369                     flag=0;
    370                     mTV_pulse.setText("脉冲数是" + String.valueOf(beats));
    371                 }
    372             } else if (imgAvg > rollingAverage) {
    373                 newType = TYPE.GREEN;
    374             }
    375 
    376             if(averageIndex == averageArraySize) {
    377                 averageIndex = 0;
    378             }
    379             averageArray[averageIndex] = imgAvg;
    380             averageIndex++;
    381 
    382             if (newType != currentType) {
    383                 currentType = newType;
    384             }
    385 
    386             //获取系统结束时间(ms)
    387             long endTime = System.currentTimeMillis();
    388             double totalTimeInSecs = (endTime - startTime) / 1000d;
    389             if (totalTimeInSecs >= 2) {
    390                 double bps = (beats / totalTimeInSecs);
    391                 int dpm = (int) (bps * 60d);
    392                 if (dpm < 30 || dpm > 180|| imgAvg < 200) {
    393                     //获取系统开始时间(ms)
    394                     startTime = System.currentTimeMillis();
    395                     //beats心跳总数
    396                     beats = 0;
    397                     processing.set(false);
    398                     return;
    399                 }
    400 
    401                 if(beatsIndex == beatsArraySize) {
    402                     beatsIndex = 0;
    403                 }
    404                 beatsArray[beatsIndex] = dpm;
    405                 beatsIndex++;
    406 
    407                 int beatsArrayAvg = 0;
    408                 int beatsArrayCnt = 0;
    409                 for (int i = 0; i < beatsArray.length; i++) {
    410                     if (beatsArray[i] > 0) {
    411                         beatsArrayAvg += beatsArray[i];
    412                         beatsArrayCnt++;
    413                     }
    414                 }
    415                 int beatsAvg = (beatsArrayAvg / beatsArrayCnt);
    416                 mTV_Heart_Rate.setText("您的心率是"+String.valueOf(beatsAvg) +
    417                         "  值:" + String.valueOf(beatsArray.length) +
    418                         "    " + String.valueOf(beatsIndex) +
    419                         "    " + String.valueOf(beatsArrayAvg) +
    420                         "    " + String.valueOf(beatsArrayCnt));
    421                 //获取系统时间(ms)
    422                 startTime = System.currentTimeMillis();
    423                 beats = 0;
    424             }
    425             processing.set(false);
    426         }
    427     };
    428 
    429     /**
    430      * 预览回调接口
    431      */
    432     private static SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
    433         //创建时调用
    434         @Override
    435         public void surfaceCreated(SurfaceHolder holder) {
    436             try {
    437                 camera.setPreviewDisplay(previewHolder);
    438                 camera.setPreviewCallback(previewCallback);
    439             } catch (Throwable t) {
    440                 Log.e("PreviewDemo","Exception in setPreviewDisplay()", t);
    441             }
    442         }
    443 
    444         //当预览改变的时候回调此方法
    445         @Override
    446         public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
    447             Camera.Parameters parameters = camera.getParameters();
    448             parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
    449             Camera.Size size = getSmallestPreviewSize(width, height, parameters);
    450             if (size != null) {
    451                 parameters.setPreviewSize(size.width, size.height);
    452             }
    453             camera.setParameters(parameters);
    454             camera.startPreview();
    455         }
    456 
    457         //销毁的时候调用
    458         @Override
    459         public void surfaceDestroyed(SurfaceHolder holder) {
    460 
    461         }
    462     };
    463 
    464     /**
    465      * 获取相机最小的预览尺寸
    466      */
    467     private static Camera.Size getSmallestPreviewSize(int width, int height, Camera.Parameters parameters) {
    468         Camera.Size result = null;
    469         for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
    470             if (size.width <= width && size.height <= height) {
    471                 if (result == null) {
    472                     result = size;
    473                 }
    474                 else {
    475                     int resultArea = result.width * result.height;
    476                     int newArea = size.width * size.height;
    477                     if (newArea < resultArea) {
    478                         result = size;
    479                     }
    480                 }
    481             }
    482         }
    483         return result;
    484     }
    485 }
  • 相关阅读:
    简单修改 MySQL 的 root 账号密码
    树莓派 Raspberry-Pi 折腾系列:系统安装及一些必要的配置
    [原创] JavaScript 图片放大镜插件 enlarge.js 以及移动版 enlarge.touch.js
    丢掉 WinPE,使用 DISKPART 来分区吧
    【原创】只用 HTML / CSS 画出一把 UKULELE(夏威夷四弦吉他)
    用网页模拟手机(安卓)通知列表中的「清除」效果
    关于 Google Chrome 中的全屏模式和 APP 模式
    简单好用的 AJAX 上传插件,还可以抛弃难看的 file 按钮哦~
    C# 操作 Excel 常见问题收集和整理(定期更新,欢迎交流)
    C++:几种callable实现方式的性能对比
  • 原文地址:https://www.cnblogs.com/hemeiwolong/p/12897834.html
Copyright © 2011-2022 走看看