com.wallerlab.compcellscope.MultiModeViewActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.wallerlab.compcellscope.MultiModeViewActivity.java

Source

/*
 * Developed as part of the Computational CellScope Project
 * Waller Lab, EECS Dept., The University of California at Berkeley
 *
 * Licensed under the 3-Clause BSD License:
 *
 * Copyright  2015 Regents of the University of California
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the owner nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */

package com.wallerlab.compcellscope;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Range;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.imgproc.Imgproc;

import com.wallerlab.compcellscope.bluetooth.BluetoothService;
import com.wallerlab.compcellscope.dialogs.AcquireSettings.NoticeDialogListener;
import com.wallerlab.compcellscope.surfaceviews.AcquireSurfaceView;
import com.wallerlab.compcellscope.MultiModeView;

import android.app.Activity;
import android.app.DialogFragment;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MultiModeViewActivity extends Activity
        implements OnTouchListener, NoticeDialogListener, CvCameraViewListener2 {

    private static final String TAG = "cCS_MultimodeView";
    private static final boolean D = true;
    private Camera mCamera;
    private AcquireSurfaceView mPreview;
    private BluetoothService mBluetoothService = null;
    private String acquireType = "MultiMode";
    Button btnSetup, btnAcquire;
    private TextView acquireTextView;
    private TextView acquireTextView2;
    private TextView timeLeftTextView;
    private ProgressBar acquireProgressBar;

    public double objectiveNA = 0.3;
    public double brightfieldNA = 0.25; // Account for LED size to be sure we completly cover NA .025

    public int ledCount = 508;
    public int centerLED = 249;
    PictureCallback rawCallback;
    ShutterCallback shutterCallback;
    PictureCallback jpegCallback;
    public String fileName = "default";
    public boolean cameraReady = true;
    public int mmCount = 5;
    public float mmDelay = 0.0f;
    public String datasetName = "Dataset";

    private int frameNum = 1;
    private boolean dpcSwitch = false;
    private static final int VIEW_MODE_RGBA = 0;
    private static final int VIEW_MODE_GRAY = 1;
    private static final int VIEW_MODE_CANNY = 2;
    private static final int VIEW_MODE_FEATURES = 5;

    private Mat mRgba;
    private Mat mIntermediateMat;
    private Mat dpcLeft;
    private Mat dpcRight;
    private Mat dpcTop;
    private Mat dpcBottom;
    private Mat mmGrid;
    private Mat dpcLRImg;
    private Mat dpcTBImg;
    private Mat bfImg;
    private Mat dfImg;

    private MenuItem mItemPreviewRGBA;
    private MenuItem mItemPreviewGray;
    private MenuItem mItemPreviewCanny;
    private MenuItem mItemPreviewFeatures;

    public int horzCrop = 0;
    public int vertCrop = 300;

    private Rect TLRect;
    private Rect TRRect;
    private Rect BLRect;
    private Rect BRRect;
    private int viewMode = 0;
    private boolean updateTrig = false;

    private Size sz;

    private MultiModeView mOpenCvCameraView;

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV loaded successfully");
                mOpenCvCameraView.enableView();
                mOpenCvCameraView.setOnTouchListener(MultiModeViewActivity.this);
            }
                break;
            default: {
                super.onManagerConnected(status);
            }
                break;
            }
        }
    };

    public MultiModeViewActivity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.multimode_liveview_layout);

        mOpenCvCameraView = (MultiModeView) findViewById(R.id.mmCameraView);

        mOpenCvCameraView.setCvCameraViewListener(this);
        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);

        mOpenCvCameraView.setCvCameraViewListener(this);

        GlobalApplicationClass BTAppClass = (GlobalApplicationClass) getApplication();
        mBluetoothService = BTAppClass.getBluetoothService();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.i(TAG, "called onCreateOptionsMenu");
        mItemPreviewRGBA = menu.add("Preview RGBA");
        mItemPreviewGray = menu.add("Preview GRAY");
        mItemPreviewCanny = menu.add("Canny");
        mItemPreviewFeatures = menu.add("Find features");
        return true;
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    public void onCameraViewStarted(int width, int height) {

        mRgba = new Mat(height, width, CvType.CV_8UC4);
        sz = new Size(width, height); //960x1280 (5) 480x800 (4)
        mIntermediateMat = new Mat(height, width, CvType.CV_16UC4);

        dpcLeft = new Mat(height, width, CvType.CV_8UC4);
        dpcRight = new Mat(height, width, CvType.CV_8UC4);
        dpcTop = new Mat(height, width, CvType.CV_8UC4);
        dpcBottom = new Mat(height, width, CvType.CV_8UC4);

        mmGrid = new Mat(height, width, CvType.CV_8UC4);

        bfImg = new Mat(height, width, CvType.CV_8UC4);
        dfImg = new Mat(height, width, CvType.CV_8UC4);
        dpcLRImg = new Mat(height, width, CvType.CV_8UC4);
        dpcTBImg = new Mat(height, width, CvType.CV_8UC4);

        TLRect = new Rect(0, 0, width / 2, height / 2);
        TRRect = new Rect(width / 2, 0, width / 2, height / 2);
        BLRect = new Rect(0, height / 2, width / 2, height / 2);
        BRRect = new Rect(width / 2, height / 2, width / 2, height / 2);

        mCamera = mOpenCvCameraView.getCameraObject();
        //Set Exposure
        sendData("bf");
        Camera.Parameters camParams;
        camParams = mCamera.getParameters();
        camParams.setAutoExposureLock(false);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //camParams.setAutoExposureLock(true);
        mCamera.setParameters(camParams);

    }

    public void onCameraViewStopped() {
        mRgba.release();
        mIntermediateMat.release();
        sendData("xx");
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

        mCamera = mOpenCvCameraView.getCameraObject();
        mRgba = inputFrame.rgba();

        Camera.Parameters camParams;
        camParams = mCamera.getParameters();

        int bfCompensation = 0;
        int dfCompensation = 0 * camParams.getMaxExposureCompensation();

        if (viewMode == 0) {
            switch (frameNum) {
            case 1: // Left
            {
                mRgba.copyTo(dpcLeft);
                sendData("dr");
                frameNum = 2;
                break;
            }
            case 2: // Right
            {
                mRgba.copyTo(dpcRight);
                sendData("dt");
                frameNum = 3;
                break;
            }
            case 3: // Top
            {
                mRgba.copyTo(dpcTop);
                sendData("db");
                frameNum = 4;
                break;
            }
            case 4: // Bottom
            {
                mRgba.copyTo(dpcBottom);
                sendData("bf");
                camParams.setExposureCompensation(bfCompensation);
                mCamera.setParameters(camParams);
                frameNum = 5;
                break;
            }
            case 5: // Brightfield
            {
                camParams.setExposureCompensation(dfCompensation);
                mCamera.setParameters(camParams);
                mRgba.copyTo(bfImg);
                sendData("an");

                frameNum = 6;
                break;
            }
            case 6: // Darkfield
            {
                mRgba.copyTo(dfImg);
                sendData("dl");

                frameNum = 1;
                break;
            }
            }
            //dpcLRImg = calcDPC(dpcLeft, dpcRight,dpcLRImg);
            new calcDPCTask().execute(dpcLeft, dpcRight, dpcLRImg);
            new calcDPCTask().execute(dpcTop, dpcBottom, dpcTBImg);
        } else {
            switch (viewMode) {
            case 1: {
                dpcSwitch = !dpcSwitch;
                if (dpcSwitch) {
                    sendData("dl");
                    mRgba.copyTo(dpcLeft);
                } else {
                    sendData("dr");
                    mRgba.copyTo(dpcRight);
                }
                new calcDPCTask().execute(dpcLeft, dpcRight, dpcLRImg);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //dpcLRImg = calcDPC(dpcLeft, dpcRight,dpcLRImg);
                break;
            }
            case 3: {
                dpcSwitch = !dpcSwitch;
                if (dpcSwitch) {
                    sendData("db");
                    mRgba.copyTo(dpcTop);
                } else {
                    sendData("dt");
                    mRgba.copyTo(dpcBottom);
                }
                new calcDPCTask().execute(dpcTop, dpcBottom, dpcTBImg);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //dpcTBImg = calcDPC(dpcTop, dpcBottom,dpcTBImg);
                break;
            }
            case 4: {

                sendData("bf");
                mRgba.copyTo(bfImg);
                //Log.d(TAG,"Displayed bf img");
                break;
            }
            case 5: {
                if (updateTrig) {
                    sendData("an");
                    updateTrig = false;
                }
                mRgba.copyTo(dfImg);
                //Log.d(TAG,"Displayed df img");
                break;
            }
            }
        }
        mmGrid = Mat.zeros(mmGrid.size(), mmGrid.type());
        if (viewMode == 0)
            mmGrid = generateMMFrame(mmGrid, bfImg, dfImg, dpcLRImg, dpcTBImg);
        else if (viewMode == 1)
            mmGrid = dpcLRImg;
        else if (viewMode == 3)
            mmGrid = dpcTBImg;
        else if (viewMode == 4)
            mmGrid = bfImg;
        else if (viewMode == 5)
            mmGrid = dfImg;

        return mmGrid;
    }

    public Mat calcDPC(Mat in1, Mat in2, Mat out) {
        Mat Mat1 = new Mat(in1.width(), in1.height(), in1.type());
        Mat Mat2 = new Mat(in2.width(), in2.height(), in2.type());
        in1.copyTo(Mat1);
        in2.copyTo(Mat2);

        Imgproc.cvtColor(Mat1, Mat1, Imgproc.COLOR_RGBA2GRAY, 1);
        Imgproc.cvtColor(Mat2, Mat2, Imgproc.COLOR_RGBA2GRAY, 1);

        Mat output = new Mat(Mat1.width(), Mat1.height(), CvType.CV_8UC4);
        Mat dpcSum = new Mat(Mat1.width(), Mat1.height(), CvType.CV_32FC1);
        Mat dpcDifference = new Mat(Mat1.width(), Mat1.height(), CvType.CV_32FC1);
        Mat dpcImgF = new Mat(Mat1.width(), Mat1.height(), CvType.CV_32FC1);

        /*
        Log.d(TAG,String.format("Mat1 format is %.1f-%.1f, type: %d",Mat1.size().width,Mat1.size().height,Mat1.type()));
        Log.d(TAG,String.format("Mat2 format is %.1f-%.1f, type: %d",Mat2.size().width,Mat2.size().height,Mat2.type()));
        */

        // Convert to Floats
        Mat1.convertTo(Mat1, CvType.CV_32FC1);
        Mat2.convertTo(Mat2, CvType.CV_32FC1);
        Core.add(Mat1, Mat2, dpcSum);
        Core.subtract(Mat1, Mat2, dpcDifference);
        Core.divide(dpcDifference, dpcSum, dpcImgF);
        Core.add(dpcImgF, new Scalar(1.0), dpcImgF); // Normalize to 0-2.0
        Core.multiply(dpcImgF, new Scalar(110), dpcImgF); // Normalize to 0-255
        dpcImgF.convertTo(output, CvType.CV_8UC1); // Convert back into RGB
        Imgproc.cvtColor(output, output, Imgproc.COLOR_GRAY2RGBA, 4);

        dpcSum.release();
        dpcDifference.release();
        dpcImgF.release();
        Mat1.release();
        Mat2.release();

        Mat maskedImg = Mat.zeros(output.rows(), output.cols(), CvType.CV_8UC4);
        int radius = maskedImg.width() / 2 + 25;
        Core.circle(maskedImg, new Point(maskedImg.width() / 2, maskedImg.height() / 2), radius,
                new Scalar(255, 255, 255), -1, 8, 0);
        output.copyTo(out, maskedImg);
        output.release();
        maskedImg.release();
        return out;
    }

    public Mat generateMMFrame(Mat gridOut, Mat MatTL, Mat MatTR, Mat MatBL, Mat MatBR) {
        //gridOut = new Mat(100, 100, gridOut.type(), new Scalar(0,0,0));
        Mat Mat1 = new Mat(MatTL.size(), MatTL.type());
        Mat Mat2 = new Mat(MatTR.size(), MatTR.type());
        Mat Mat3 = new Mat(MatBL.size(), MatBL.type());
        Mat Mat4 = new Mat(MatBR.size(), MatBR.type());

        // Ensure all of the mats are of the correct size since pyramid operation resizes
        Imgproc.resize(MatTL, MatTL, sz);
        Imgproc.resize(MatTR, MatTR, sz);
        Imgproc.resize(MatBL, MatBL, sz);
        Imgproc.resize(MatBR, MatBR, sz);

        // Downsample by 2 for 2x2 grid
        Imgproc.pyrDown(MatBL, Mat1);
        Imgproc.pyrDown(MatBR, Mat2);
        Imgproc.pyrDown(MatTL, Mat3);
        Imgproc.pyrDown(MatTR, Mat4);

        /*
        Log.d(TAG,String.format("TLRect format is %.1f-%.1f",TLRect.size().width,TLRect.size().height));
        Log.d(TAG,String.format("TRRect format is %.1f-%.1f",TRRect.size().width,TRRect.size().height));
            
        Log.d(TAG,String.format("BLRect format is %.1f-%.1f",BLRect.size().width,BLRect.size().height));
        Log.d(TAG,String.format("BRRect format is %.1f-%.1f",BRRect.size().width,BRRect.size().height));
            
        Log.d(TAG,String.format("MatTL format is %.1f-%.1f",MatTL.size().width,MatTL.size().height));
        Log.d(TAG,String.format("MatTR format is %.1f-%.1f",MatTR.size().width,MatTR.size().height));
            
        Log.d(TAG,String.format("MatBL format is %.1f-%.1f",MatBL.size().width,MatBL.size().height));
        Log.d(TAG,String.format("MatBR format is %.1f-%.1f",MatBR.size().width,MatBR.size().height));
         */

        Core.putText(Mat1, "DPC-LR", new Point(43, 40), Core.FONT_ITALIC, 1, new Scalar(255, 255, 0));
        Core.putText(Mat2, "DPC-TB", new Point(43, 40), Core.FONT_ITALIC, 1, new Scalar(255, 255, 0));
        Core.putText(Mat3, "BrightField", new Point(33, 40), Core.FONT_ITALIC, 1, new Scalar(255, 255, 0));
        Core.putText(Mat4, "DarkField", new Point(37, 40), Core.FONT_ITALIC, 1, new Scalar(255, 255, 0));

        Mat1.copyTo(gridOut.submat(BLRect));
        Mat2.copyTo(gridOut.submat(BRRect));
        Mat3.copyTo(gridOut.submat(TLRect));
        Mat4.copyTo(gridOut.submat(TRRect));

        Mat1.release();
        Mat2.release();
        Mat3.release();
        Mat4.release();

        return gridOut;
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
        /*
        if (item == mItemPreviewRGBA) {
        mViewMode = VIEW_MODE_RGBA;
        } else if (item == mItemPreviewGray) {
        mViewMode = VIEW_MODE_GRAY;
        } else if (item == mItemPreviewCanny) {
        mViewMode = VIEW_MODE_CANNY;
        } else if (item == mItemPreviewFeatures) {
        mViewMode = VIEW_MODE_FEATURES;
        }
        */
        return true;
    }

    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            if (viewMode == 0) {
                updateTrig = true;
                // Determine set new view based on where the user touched
                if ((int) event.getY() < v.getHeight() / 2) {
                    if ((int) event.getX() > v.getWidth() / 2) {
                        viewMode = 5;
                        Camera.Parameters camParams = mCamera.getParameters();
                        camParams.setExposureCompensation(-6);
                        mCamera.setParameters(camParams);
                    } else {
                        viewMode = 4;
                        Camera.Parameters camParams = mCamera.getParameters();
                        camParams.setExposureCompensation(0);
                        mCamera.setParameters(camParams);
                    }
                } else {
                    Camera.Parameters camParams = mCamera.getParameters();
                    camParams.setExposureCompensation(0);
                    mCamera.setParameters(camParams);
                    if ((int) event.getX() > v.getWidth() / 2)
                        viewMode = 3;
                    else
                        viewMode = 1;
                }
            } else {
                Camera.Parameters camParams = mCamera.getParameters();
                camParams.setExposureCompensation(0);
                mCamera.setParameters(camParams);
                viewMode = 0; // Set back to multimode display
            }
        }
        return false;
    }

    public void sendData(String message) {
        message = message + "\n";
        // Check that we're actually connected before trying anything
        if (mBluetoothService.getState() != BluetoothService.STATE_CONNECTED) {
            Toast.makeText(this, "NOT CONNECTED", Toast.LENGTH_SHORT).show();
            return;
        }
        // Check that there's actually something to send
        if (message.length() > 0) {
            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mBluetoothService.write(send);
        }
    }

    //fire intent to start activity with proper configuration for acquire type
    protected void startGalleryActivity() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(
                Uri.parse("file://" + Environment.getExternalStorageDirectory() + "/CellScope/20140815_163448496/"),
                "image/*");
        startActivity(intent);
    }

    public void updateFileStructure(String currPath) {
        File f = new File(currPath);
        File[] fileList = f.listFiles();
        ArrayList<String> arrayFiles = new ArrayList<String>();
        if (!(fileList.length == 0)) {
            for (int i = 0; i < fileList.length; i++)
                arrayFiles.add(currPath + "/" + fileList[i].getName());
        }

        String[] fileListString = new String[arrayFiles.size()];
        fileListString = arrayFiles.toArray(fileListString);
        MediaScannerConnection.scanFile(MultiModeViewActivity.this, fileListString, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    public void onScanCompleted(String path, Uri uri) {
                        //Log.i("TAG", "Finished scanning " + path);
                    }
                });
    }

    public void openSettingsDialog() {
        //settingsDialogFragment.show(getFragmentManager(), "acquireSettings");
    }

    public void setNA(float na) {
        brightfieldNA = na;
        sendData(String.format("na,%d", (int) Math.round(na * 100)));
    }

    public void setMultiModeDelay(float delay) {
        mmDelay = delay;
    }

    public void setDatasetName(String name) {
        datasetName = name;
    }

    public void toggleBrightfield() {
        sendData("bf");
        Camera.Parameters camParams = mCamera.getParameters();
        camParams.setAutoExposureLock(false);
        mCamera.setParameters(camParams);
    }

    public void toggleDarkfield() {
        sendData("df");
        Camera.Parameters camParams = mCamera.getParameters();
        camParams.setAutoExposureLock(false);
        mCamera.setParameters(camParams);
    }

    public void toggleAlignment() {
        // TODO - add alignment routine
        sendData("xx");
    }
}