【问题标题】:Handling OnPreview method in camera2 API在 camera2 API 中处理 OnPreview 方法
【发布时间】:2019-01-10 17:02:29
【问题描述】:

我无法从相机获取预览数据。我正在使用相机 2 api 使用相机镜头读取手指上的红绿色强度。我 我正在开发一个可以使用一些图像处理算法来读取血压的应用程序。应用程序在启动预览活动时崩溃。

    package com.example.jacksonmwirigi.bpdiagnosisapp;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.ImageFormat;
    import android.graphics.Interpolator;
    import android.graphics.SurfaceTexture;
    import android.hardware.camera2.CameraAccessException;
    import android.hardware.camera2.CameraCaptureSession;
    import android.hardware.camera2.CameraCharacteristics;
    import android.hardware.camera2.CameraDevice;
    import android.hardware.camera2.CameraManager;
    import android.hardware.camera2.CaptureRequest;
    import android.hardware.camera2.params.StreamConfigurationMap;
    import android.media.Image;
    import android.media.ImageReader;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.PowerManager;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.media.MediaBrowserServiceCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Size;
    import android.view.Surface;
    import android.view.TextureView;
    import android.widget.ProgressBar;
    import android.widget.Toast;
    import com.example.jacksonmwirigi.bpdiagnosisapp.Math.Fft;
    import java.nio.ByteBuffer;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.concurrent.atomic.AtomicBoolean;

    import javax.xml.transform.Result;

    import static java.lang.Math.ceil;


    public class BPPTest extends AppCompatActivity  {

    static final int MY_PERMISSIONS_REQUEST_CAMERA = 1242;

    private TextureView mSurfaceView;
    private CameraManager mCameraManager;
    private TextureView.SurfaceTextureListener surfaceTextureListener;
    private static CameraDevice mCameraDevice;
    private CameraDevice.StateCallback mCameraStateCB;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder captureRequestBuilder;
    private CaptureRequest captureRequest;
    private Size previewSize;
    private String cameraId;
    private Handler backgroundHandler;
    private HandlerThread backgroundThread;
    int cameraFacing;
    ImageReader imageReader;
    // Variables Initialization
    private static final String TAG = "HeartRateMonitor";
    private static final AtomicBoolean processing = new AtomicBoolean(false);
    private static PowerManager.WakeLock wakeLock = null;

    //Toast
    private Toast mainToast;

    //DataBase
    public String user;
    UserDB Data = new UserDB(this);

    //ProgressBar
    private ProgressBar ProgBP;
    public int ProgP =0;
    public int inc=0;

    //Beats variable
    public int Beats=0;
    public double bufferAvgB=0;

    //Freq + timer variable
    private static long startTime = 0;
    private double SamplingFreq;

    //BloodPressure variables
    public double Gen,Agg,Hei,Wei;
    public double Q =4.5;
    private static int SP = 0, DP = 0;

    //Arraylist
    public ArrayList<Double> GreenAvgList=new ArrayList<Double>();
    public ArrayList<Double> RedAvgList=new ArrayList<Double>();

    public int counter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bpptest);

        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            user = extras.getString("Usr");
            //The key argument here must match that used in the other activity
        }

        Hei = Integer.parseInt(Data.getheight(user));
        Wei = Integer.parseInt(Data.getweight(user));
        Agg = Integer.parseInt(Data.getage(user));
        Gen = Integer.parseInt(Data.getgender(user));

        if (Gen == 1) {
            Q = 5;
        }

 mSurfaceView.getHeight(), ImageFormat.YUV_420_888, 2);
        mSurfaceView = (TextureView) findViewById(R.id.SurfaceViewPreview);
        ProgBP = (ProgressBar) findViewById(R.id.BPPB);
        ProgBP.setProgress(0);

// ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},CAMERA_REQUEST_CODE);
        mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
        cameraFacing = CameraCharacteristics.LENS_FACING_BACK;

        surfaceTextureListener = new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {

                setUpCamera(width, height);
                openCamera();
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        };

        mCameraStateCB = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice camera) {

                mCameraDevice=camera;
                createPreviewSession();
            }

            @Override
            public void onDisconnected(CameraDevice camera) {

                mCameraDevice = camera;
                mCameraDevice.close();
                mCameraDevice = null;

            }

            @Override
            public void onError(CameraDevice camera, int error) {

                mCameraDevice = camera;
                mCameraDevice.close();
                mCameraDevice = null;
            }
        };
    }

private void setUpCamera(int width, int height) {
        try {
 for (String cameraId : mCameraManager.getCameraIdList()) {
                                      mCameraManager.getCameraCharacteristics(cameraId);

if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
                        cameraFacing) {
                    StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(
                            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                    previewSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class)[0];
                    this.cameraId = cameraId;
                }

            }
        } catch (CameraAccessException e) {

            e.printStackTrace();
        }

    }
private void openCamera() {

 //requesting permission
 int permissionCheck = ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA);
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.CAMERA)) {
 } else {
  ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_CAMERA);
                Toast.makeText(getApplicationContext(), "request permission", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(getApplicationContext(), "PERMISSION_ALREADY_GRANTED", Toast.LENGTH_SHORT).show();
            try {
                mCameraManager.openCamera(cameraId, mCameraStateCB, backgroundHandler);

            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

    }


    @Override
    protected void onResume() {
        super.onResume();

        openBackgroundThread();
        if (mSurfaceView.isAvailable()) {
            setUpCamera(mSurfaceView.getWidth(),mSurfaceView.getHeight());
            openCamera();
        } else {
            mSurfaceView.setSurfaceTextureListener(surfaceTextureListener);
        }


    }


    @Override
    protected void onStop() {
        super.onStop();

        closeCamera();
        closeBackgroundThread();
    }


    private void closeCamera() {
        if (cameraCaptureSession != null) {
            cameraCaptureSession.close();
            cameraCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }
    private void createPreviewSession( ) {

         int width = mSurfaceView.getWidth();
         int height = mSurfaceView.getWidth();
         byte[] data =new byte[width*height];

    try {

    SurfaceTexture surface=mSurfaceView.getSurfaceTexture();
    surface.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
    Surface  previewSurface = new Surface(surface);

    captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    captureRequestBuilder.addTarget(previewSurface);

    mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {

            if (mCameraDevice == null) {
                return;
            }

            cameraCaptureSession=session;

            try{

                captureRequest = captureRequestBuilder.build();
                cameraCaptureSession.setRepeatingRequest(captureRequest,null, backgroundHandler);

                //Atomically sets the value to the given updated value if the current value == the expected value.
                if (!processing.compareAndSet(false, true)) return;

                //put width + height of the camera inside the variables
                double GreenAvg;
                double RedAvg; GreenAvg=ImageProcessing.decodeYUV420SPtoRedBlueGreenAvg(data.clone(), height, width,3);
                //1 stands for red intensity, 2 for blue, 3 for green
                RedAvg=ImageProcessing.decodeYUV420SPtoRedBlueGreenAvg(data.clone(), height, width,1);
                //1 stands for red intensity, 2 for blue, 3 for green

                GreenAvgList.add(GreenAvg);
                RedAvgList.add(RedAvg);

                ++counter; //countes number of frames in 30 seconds


                //To check if we got a good red intensity to process if not return to the condition and set it again until we get a good red intensity
                if (RedAvg < 200) {
                    inc=0;
                    ProgP=inc;
                    counter=0;
                    ProgBP.setProgress(ProgP);
                    processing.set(false);
                }

                long endTime = System.currentTimeMillis();
                double totalTimeInSecs = (endTime - startTime) / 1000d; //to convert time to seconds
                if (totalTimeInSecs >= 30) { //when 30 seconds of measuring passes do the following " we chose 30 seconds to take half sample since 60 seconds is normally a full sample of the heart beat


                    Double[] Green = GreenAvgList.toArray(new Double[GreenAvgList.size()]);
                    Double[] Red = RedAvgList.toArray(new Double[RedAvgList.size()]);

                    SamplingFreq =  (counter/totalTimeInSecs); //calculating the sampling frequency

                    double HRFreq = Fft.FFT(Green, counter, SamplingFreq); // send the green array and get its fft then return the amount of heartrate per second
                    double bpm=(int)ceil(HRFreq*60);
                    double HR1Freq = Fft.FFT(Red, counter, SamplingFreq);  // send the red array and get its fft then return the amount of heartrate per second
                    double bpm1=(int)ceil(HR1Freq*60);



                    // The following code is to make sure that if the heartrate from red and green intensities are reasonable
                    // take the average between them, otherwise take the green or red if one of them is good

                    if((bpm > 45 || bpm < 200) )
                    {
                        if((bpm1 > 45 || bpm1 < 200)) {

                            bufferAvgB = (bpm+bpm1)/2;
                        }
                        else{
                            bufferAvgB = bpm;
                        }

                    }
                    else if((bpm1 > 45 || bpm1 < 200)){

                        bufferAvgB = bpm1;

                    }
                    if (bufferAvgB < 45 || bufferAvgB > 200) {
                        inc=0;
                        ProgP=inc;
                        ProgBP.setProgress(ProgP);
                        mainToast = Toast.makeText(getApplicationContext(), "Measurement Failed", Toast.LENGTH_SHORT);
                        mainToast.show();
                        startTime = System.currentTimeMillis();
                        counter=0;
                        processing.set(false);
                        return;
                    }

                    Beats=(int)bufferAvgB;

                    double ROB = 18.5;
                    double ET = (364.5-1.23*Beats);
                    double BSA = 0.007184*(Math.pow(Wei,0.425))*(Math.pow(Hei,0.725));
                    double SV = (-6.6 + (0.25*(ET-35)) - (0.62*Beats) + (40.4*BSA) - (0.51*Agg));
                    double PP = SV / ((0.013*Wei - 0.007*Agg-0.004*Beats)+1.307);
                    double MPP = Q*ROB;

                    SP = (int) (MPP + 3/2*PP);
                    DP = (int) (MPP - PP/3);

                }

                if((SP != 0) && (DP != 0)){
                    Intent i=new Intent(BPPTest.this,BloodPressureResult.class);
                    i.putExtra("SP", SP);
                    i.putExtra("DP", DP);
                    i.putExtra("Usr", user);
                    startActivity(i);
                    finish();}


                if(RedAvg!=0){
                    ProgP=inc++/34;
                    ProgBP.setProgress(ProgP);}
                processing.set(false);

            }



            catch (CameraAccessException e) {
                e.printStackTrace();
            }


        }
        @Override
        public void onConfigureFailed(CameraCaptureSession session) {
        }
       },    backgroundHandler);

    }catch (CameraAccessException e){

       e.printStackTrace();
       }

    } private void openBackgroundThread() {
        backgroundThread = new HandlerThread("camera_background_thread");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());


    }

    private void closeBackgroundThread() {
        if (backgroundHandler != null) {
            backgroundThread.quitSafely();
            backgroundThread = null;
            backgroundHandler = null;

        }
      }



    @Override
    public void onBackPressed() {
        super.onBackPressed();

        Intent i = new Intent(BPPTest.this, StartVitalSigns.class);
        startActivity(i);

       }
    }

【问题讨论】:

  • 请从系统日志中实际包含您的崩溃错误。

标签: android


【解决方案1】:

当我有一个显示预览的 TextureView 时,我会这样做以从相机中获取每一帧。 我在textureCameraPreview 中添加了一个SurfaceTextureListener,并在覆盖方法onSurfaceTextureUpdated 中添加了这个:

        @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        //Continuously read every frame of the camera2 surface view and detect the image
        Bitmap myBitmap = textureCameraPreview.getBitmap();
        //Do something with the obtained bitmap.
    }

您也可以使用ImageReader 来获取帧,但实现更复杂。这应该足够了,就我个人而言,无论是使用 ImageReader 实现还是这个实现都没有区别,所以我选择了使用更少代码和更具可读性的那个。但是,如果您想在纹理上叠加某些内容,则需要查看 MLKit 的示例应用程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多