com.wallerlab.processing.tasks.ComputeRefocusTask.java Source code

Java tutorial

Introduction

Here is the source code for com.wallerlab.processing.tasks.ComputeRefocusTask.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.processing.tasks;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.SystemClock;
import android.util.Log;

import com.wallerlab.processing.datasets.Dataset;
import com.wallerlab.processing.utilities.ImageUtils;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class ComputeRefocusTask extends ImageProgressTask {
    private static final String TAG = "ComputeRefocusTask";

    public ComputeRefocusTask(Context context) {
        super(context);
        this.progressDialog.setMessage("Assembling refocused images...");
    }

    Dataset mDataset = null;
    double tanh_lit[];
    double tanv_lit[];
    byte[][] fileByteList;

    @Override
    protected Void doInBackground(Dataset... params) {
        mDataset = params[0];

        float zMin = mDataset.ZMIN;
        float zInc = mDataset.ZINC;
        float zMax = mDataset.ZMAX;
        String outDir = mDataset.DATASET_PATH + "/Refocused/";
        File outFile = new File(outDir);
        outFile.mkdirs();

        // Build rotation matrix
        double globalRotation = Math.PI / 4;
        double rotationTransform[][] = new double[3][3];
        rotationTransform[0][0] = Math.cos(globalRotation);
        rotationTransform[0][1] = -1 * Math.sin(globalRotation);
        rotationTransform[0][2] = 0.0;
        rotationTransform[1][0] = Math.sin(globalRotation);
        rotationTransform[1][1] = Math.cos(globalRotation);
        rotationTransform[1][2] = 0.0;
        rotationTransform[2][0] = 0.0;
        rotationTransform[2][1] = 0.0;
        rotationTransform[2][2] = 1.0;

        double rotatedCoordinates[][] = new double[mDataset.domeCoordinates.length][3];
        double domeCoordinates[][] = new double[mDataset.domeCoordinates.length][3];

        // Convert the coordinates to floats
        for (int i = 0; i < mDataset.domeCoordinates.length; i++) {
            domeCoordinates[i][0] = mDataset.domeCoordinates[i][0];
            domeCoordinates[i][1] = mDataset.domeCoordinates[i][1];
            domeCoordinates[i][2] = mDataset.domeCoordinates[i][2];
        }

        rotatedCoordinates = ImageUtils.multiplyArray(domeCoordinates, rotationTransform);

        tanh_lit = new double[mDataset.domeCoordinates.length];
        tanv_lit = new double[mDataset.domeCoordinates.length];

        for (int i = 0; i < mDataset.domeCoordinates.length; i++) {
            tanh_lit[i] = rotatedCoordinates[i][0] / rotatedCoordinates[i][2];
            tanv_lit[i] = rotatedCoordinates[i][1] / rotatedCoordinates[i][2];
        }

        //TODO - Load as many images into ram as possible
        //TODO - load compressed images rather than mats
        fileByteList = new byte[mDataset.fileCount][(int) mDataset.fileList[0].length() * 2];

        for (int idx = 0; idx < mDataset.fileCount; idx++) {

            File file = mDataset.fileList[idx];
            int size = (int) file.length();
            byte[] bytes = new byte[size];
            try {
                BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
                buf.read(bytes, 0, bytes.length);
                buf.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            fileByteList[idx] = bytes;

        }
        long startTime = SystemClock.elapsedRealtime();
        for (float z = zMin; z <= zMax; z += zInc) {
            float progress = (z - zMin) / (zMax - zMin);
            onProgressUpdate(-1, (int) (progress * 100));
            Bitmap[] results = computeFocus(z);

            // Build Filename Structure
            long time = SystemClock.elapsedRealtime() - startTime;
            String refocused_fName = String.format("%s%srefocused_(%d)_%3d.png", outDir, mDataset.DATASET_HEADER,
                    (int) (z - zMin), time);
            String dpc_tb_fName = String.format("%s%sdpc_tb_(%d)_%3d.png", outDir, mDataset.DATASET_HEADER,
                    (int) (z - zMin), time);
            String dpc_lr_fName = String.format("%s%sdpc_lr_(%d)_%3d.png", outDir, mDataset.DATASET_HEADER,
                    (int) (z - zMin), time);

            // Gen file object
            File refocusedBmp = new File(refocused_fName);
            File dpc_tb_Bmp = new File(dpc_tb_fName);
            File dpc_lr_Bmp = new File(dpc_lr_fName);

            try {
                FileOutputStream fos = new FileOutputStream(refocusedBmp);
                results[0].compress(Bitmap.CompressFormat.PNG, 100, fos);
            } catch (FileNotFoundException e) {
                Log.d(TAG, String.format("File Not found exception. Name: %s", refocused_fName));
                return null;
            }
            try {
                FileOutputStream fos = new FileOutputStream(dpc_lr_Bmp);
                results[1].compress(Bitmap.CompressFormat.PNG, 100, fos);
            } catch (FileNotFoundException e) {
                Log.d(TAG, String.format("File Not found exception. Name: %s", dpc_lr_fName));
                return null;
            }
            try {
                FileOutputStream fos = new FileOutputStream(dpc_tb_Bmp);
                results[2].compress(Bitmap.CompressFormat.PNG, 100, fos);
            } catch (FileNotFoundException e) {
                Log.d(TAG, String.format("File Not found exception. Name: %s", dpc_tb_fName));
                return null;
            }
        }
        updateFileStructure(outDir);
        return null;
    }

    private Bitmap[] computeFocus(float z) {
        int width = mDataset.WIDTH - 2 * mDataset.XCROP;
        int height = mDataset.HEIGHT - 2 * mDataset.YCROP;

        Mat result = new Mat(height, width, CvType.CV_32FC4);
        Mat result8 = new Mat(height, width, CvType.CV_8UC4);

        Mat dpc_result_tb = new Mat(height, width, CvType.CV_32FC4);
        Mat dpc_result_tb8 = new Mat(height, width, CvType.CV_8UC4);

        Mat dpc_result_lr = new Mat(height, width, CvType.CV_32FC4);
        Mat dpc_result_lr8 = new Mat(height, width, CvType.CV_8UC4);

        Mat img;
        Mat img32 = new Mat(height, width, CvType.CV_32FC4);
        Mat shifted;

        for (int idx = 0; idx < mDataset.fileCount; idx++) {
            img = ImageUtils.toMat(BitmapFactory.decodeByteArray(fileByteList[idx], 0, fileByteList[idx].length));
            img = img.submat(mDataset.YCROP, mDataset.HEIGHT - mDataset.YCROP, mDataset.XCROP,
                    mDataset.WIDTH - mDataset.XCROP);
            img.convertTo(img32, result.type());

            // Grab actual hole number from filename
            String fName = mDataset.fileList[idx].toString();
            String hNum = fName.substring(fName.indexOf("_scanning_") + 10, fName.indexOf(".jpeg"));
            int holeNum = Integer.parseInt(hNum);
            //Log.d(TAG,String.format("BF Scan Header is: %s", hNum));

            // Calculate these based on array coordinates
            int xShift = (int) Math.round(z * tanh_lit[holeNum]);
            int yShift = (int) Math.round(z * tanv_lit[holeNum]);

            shifted = ImageUtils.circularShift(img32, yShift, xShift);

            if (mDataset.leftList.contains(holeNum)) //add LHS
            {
                Core.add(dpc_result_lr, shifted, dpc_result_lr);
            } else //subtract RHS
            {
                Core.subtract(dpc_result_lr, shifted, dpc_result_lr);
            }

            if (mDataset.topList.contains(holeNum)) //add Top
            {
                Core.add(dpc_result_tb, shifted, dpc_result_tb);
            } else //subtract bottom
            {
                Core.subtract(dpc_result_tb, shifted, dpc_result_tb);
            }

            Core.add(result, shifted, result);

            float progress = ((idx + 1) / (float) mDataset.fileCount);
            onProgressUpdate((int) (progress * 100), -1);
            Log.d(TAG, String.format("progress: %f", progress));
        }

        Core.MinMaxLocResult minMaxLocResult1 = Core.minMaxLoc(result.reshape(1));
        result.convertTo(result8, CvType.CV_8UC4, 255 / minMaxLocResult1.maxVal);

        Core.MinMaxLocResult minMaxLocResult2 = Core.minMaxLoc(dpc_result_lr.reshape(1));
        dpc_result_lr.convertTo(dpc_result_lr8, CvType.CV_8UC4,
                255 / (minMaxLocResult2.maxVal - minMaxLocResult2.minVal),
                -minMaxLocResult2.minVal * 255.0 / (minMaxLocResult2.maxVal - minMaxLocResult2.minVal));

        Core.MinMaxLocResult minMaxLocResult3 = Core.minMaxLoc(dpc_result_tb.reshape(1));
        dpc_result_tb.convertTo(dpc_result_tb8, CvType.CV_8UC4,
                255 / (minMaxLocResult3.maxVal - minMaxLocResult3.minVal),
                -minMaxLocResult3.minVal * 255.0 / (minMaxLocResult3.maxVal - minMaxLocResult3.minVal));

        /*
        Log.d(TAG,String.format("result_min: %f, max: %f",minMaxLocResult1.minVal,minMaxLocResult1.maxVal));
        Log.d(TAG,String.format("lr_min: %f, max: %f",minMaxLocResult2.minVal,minMaxLocResult2.maxVal));
        Log.d(TAG,String.format("tb_min: %f, max: %f",minMaxLocResult3.minVal,minMaxLocResult3.maxVal));
        */

        // remove transparency in DPC images
        Scalar alphaMask = new Scalar(new double[] { 1.0, 1.0, 1.0, 255.0 });

        Core.multiply(dpc_result_lr8, alphaMask, dpc_result_lr8);
        Core.multiply(dpc_result_tb8, alphaMask, dpc_result_tb8);

        if (!mDataset.USE_COLOR_DPC) {
            Imgproc.cvtColor(dpc_result_lr8, dpc_result_lr8, Imgproc.COLOR_BGR2GRAY);
            Imgproc.cvtColor(dpc_result_tb8, dpc_result_tb8, Imgproc.COLOR_BGR2GRAY);
        }

        /*
        // Cut off edges in DPC images
        Point centerPt = new Point();
        centerPt.x = Math.round((float)width/2.0);
        centerPt.y = Math.round((float)height/2.0);
        Mat circleMat = new Mat(dpc_result_lr8.size(), dpc_result_lr8.type());
        Scalar color = new Scalar(255);
        Core.circle(circleMat, centerPt, 200, color);
        //Core.bitwise_and(circleMat, dpc_result_lr8, dpc_result_lr8);
        //Core.bitwise_and(circleMat, dpc_result_tb8, dpc_result_tb8);
        * 
        * 
        */

        Bitmap[] outputBitmaps = new Bitmap[3];
        outputBitmaps[0] = ImageUtils.toBitmap(result8);
        outputBitmaps[1] = ImageUtils.toBitmap(dpc_result_lr8);
        outputBitmaps[2] = ImageUtils.toBitmap(dpc_result_tb8);

        return outputBitmaps;
    }

    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(context, fileListString, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    @Override
                    public void onScanCompleted(String path, Uri uri) {
                        //Log.i("TAG", "Finished scanning " + path);
                    }
                });
    }
}