Home | History | Annotate | Download | only in refocus
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.renderscript.cts.refocus;
     18 
     19 import android.util.Log;
     20 
     21 import java.util.ArrayList;
     22 
     23 /**
     24  * An object that contains all the parameters that are needed in refocusing
     25  * filtering function, including the range of depth levels, the disc blur radius
     26  * of each depth level, how the depth levels are grouped into layers, which
     27  * layer is in focus.
     28  *
     29  *  <b> Here by "depth", we mean inverse depth. Pixels with larger depth values
     30  * are closer to the camera.
     31  *
     32  *  For a layer n, its depth interval is (@code [layerInfo[n].backDepth,
     33  * layerInfo[n].frontDepth]), where (@code backDepth<=frontDepth).
     34  *
     35  *  The layers are ordered from near to far; note that near layers have larger
     36  * depth values.
     37  *
     38  *  (@code focusLayer) is the index of the layer that is in focus, that is, has
     39  * zero blur.
     40  */
     41 
     42 public class BlurStack {
     43   //private static final Log.Tag TAG = new Log.Tag("BlurStack");
     44   private static final String TAG = "BlurStack";
     45   /**
     46    * The cap for disc radius of blur kernels.
     47    */
     48   private static final float MAX_DISC_RADIUS = 25.0f;
     49 
     50   /**
     51    * The minimum of the interval that is used to group depth levels into
     52    * blending layers based on the corresponding blur disk radius.
     53    */
     54   private static final float MIN_DISK_RADIUS_STEP_SIZE = 2.0f;
     55 
     56   /**
     57    * The starting index of depth quantization level. Must be positive as zero is
     58    * reserved for invalid depth.
     59    */
     60   private static final int MIN_DEPTH = 1;
     61 
     62   /**
     63    * The ending index of depth quantization level. It must be a power of 2.
     64    */
     65   private static final int MAX_DEPTH = 64;
     66 
     67   /**
     68    * The scale to apply to 8-bit depthmaps.
     69    */
     70   private static final int DEPTH_SCALE = 256 / MAX_DEPTH;
     71 
     72   /**
     73    * For each depth value {@code d} within [MIN_DEPTH,MAX_DEPTH], its blur disc
     74    * radius is saved in {@code diskRadius[d-MIN_DEPTH]}. Hence the length
     75    * {@code diskRadius} is {@code MAX_DEPTH-MIN_DEPTH+1}.
     76    */
     77   private float[] diskRadiusArray;
     78 
     79   /**
     80    * A set of non-overlapping layers that covers all the depth levels. The
     81    * layers are ordered from front (closer to the camera) to back (farther away
     82    * from the camera).
     83    */
     84   private LayerInfo[] layerInfo;
     85 
     86   /**
     87    * The layer in which the focal depth belongs to. <b> For this layer, we
     88    * assume that it is a single depth layer. That is, the front depth and back
     89    * depth both equal to focal depth.
     90    */
     91   private int focusLayer;
     92 
     93   public static float getMaxDiskRadius() {
     94     return MAX_DISC_RADIUS;
     95   }
     96 
     97   /**
     98    * Returns the blur disk radius of a depth level.
     99    *
    100    * @param depth depth level
    101    * @return the blur disk radius of the depth level
    102    */
    103   public float getDiskRadius(int depth) {
    104     return diskRadiusArray[depth - MIN_DEPTH];
    105   }
    106 
    107   public int getNumLayers() {
    108     return layerInfo.length;
    109   }
    110 
    111   public LayerInfo getLayerInfo(int layer) {
    112     return layerInfo[layer];
    113   }
    114 
    115   /**
    116    * Returns the number of depths in a given layer.
    117    *
    118    * @param layer layer index
    119    * @return the number of depth levels in the layer
    120    */
    121   public int getNumDepths(int layer) {
    122     return layerInfo[layer].frontDepth - layerInfo[layer].backDepth + 1;
    123   }
    124 
    125   public int getFocusLayer() {
    126     return focusLayer;
    127   }
    128 
    129   /**
    130    * Returns the depth given the layer and the relative depth in the layer.
    131    *
    132    * @param layer the layer index
    133    * @param relativeDepthInLayer the relative depth index relative to the back
    134    *        depth of a layer
    135    * @return the depth
    136    */
    137   public int getDepth(int layer, int relativeDepthInLayer) {
    138     return layerInfo[layer].backDepth + relativeDepthInLayer;
    139   }
    140 
    141   /**
    142    * Creates an instance of BlurStack using depth range, focal depth, desired
    143    * amount of blur at infinity, and the number of blending layers.
    144    *
    145    * @param depthTransform an object that translates between floating depth and
    146    *        quantized depth.
    147    * @param focusDepth3D focus depth in 3D
    148    * @param depthOfField the range of depth values around focus depth 3D that
    149    *        has zero blur.
    150    * @param blurInfinity the desired amount of blur, represented as blur radius
    151    *        at infinity
    152    * @param numBlendingLayers the number of blending layers that group all the
    153    *        depth levels
    154    * @return an instance of {@code BlurStack}
    155    */
    156   public static BlurStack createFromDepthTransform(
    157       final DepthTransform depthTransform, float focusDepth3D,
    158       float depthOfField, float blurInfinity, int numBlendingLayers) {
    159     BlurStack blurStack = new BlurStack();
    160     // Finds the front and back depth levels for the focus layer.
    161     if (depthOfField < 0) {
    162       depthOfField = -depthOfField;
    163       Log.e(TAG, "Negative depth of field");
    164     }
    165     int frontFocalDepth = openglDepthToStackDepth(
    166         depthTransform.quantize(focusDepth3D * (1 - depthOfField)));
    167     int backFocalDepth = openglDepthToStackDepth(
    168         depthTransform.quantize(focusDepth3D * (1 + depthOfField)));
    169     // Computes blur disk radius for all the depth levels.
    170     blurStack.computeDiskRadius(depthTransform, frontFocalDepth, backFocalDepth,
    171         blurInfinity);
    172 
    173     if (numBlendingLayers >= MAX_DEPTH) {
    174       blurStack.generateOneLayerForEachDepth(frontFocalDepth, backFocalDepth);
    175     } else {
    176       // Sets the max variation of blur disk radius in a blending layer.
    177       float diskRadiusInterval = (blurStack.getDiskRadius(MIN_DEPTH)
    178           + blurStack.getDiskRadius(MAX_DEPTH)) / numBlendingLayers;
    179       diskRadiusInterval =
    180           Math.max(diskRadiusInterval, MIN_DISK_RADIUS_STEP_SIZE);
    181       // Computes {@code layerInfo, focusLayer}, assuming {@code diskRadius}
    182       // have been computed.
    183       blurStack.groupDepthLevelsIntoLayers(frontFocalDepth, backFocalDepth,
    184           diskRadiusInterval);
    185     }
    186     return blurStack;
    187   }
    188 
    189   @Override
    190   public String toString() {
    191     String s = "disparity range: " + MAX_DEPTH + ", " + MIN_DEPTH + "\n";
    192     s += "focus disparity: " + layerInfo[focusLayer].frontDepth + ", "
    193         + layerInfo[focusLayer].backDepth + "\n";
    194     s += "num of layers: " + getNumLayers() + "\n";
    195     s += "focus layer: " + focusLayer + "\n";
    196 
    197     for (int n = 0; n < layerInfo.length; ++n) {
    198       int front = layerInfo[n].frontDepth;
    199       int back = layerInfo[n].backDepth;
    200       s += "\nlayer " + n + " num of disparities " + (front - back + 1) + "\n";
    201 
    202       for (int d = front; d >= back; --d) {
    203         s += "layer " + n + " disparity " + d + " disk radius "
    204             + getDiskRadius(d) + "\n";
    205       }
    206     }
    207 
    208     return s;
    209   }
    210 
    211   /**
    212    * OpenGL depth is from 0(near) to 255(far). The depth in BlurStack is from
    213    * 1(far) to MAX_DEPTH(near). Converts from openglDepth to stackDepth.
    214    *
    215    * @param openglDepth openGL depth.
    216    * @return stackDepth stack depth.
    217    */
    218   private static int openglDepthToStackDepth(int openglDepth) {
    219     return MAX_DEPTH - (openglDepth / DEPTH_SCALE);
    220   }
    221 
    222   /**
    223    * OpenGL depth is from 0(near) to 255(far). The depth in BlurStack is from
    224    * 1(far) to MAX_DEPTH(near). Converts from stackDepth to openglDepth.
    225    *
    226    * @param stackDepth stack depth.
    227    * @return openglDepth openGL depth.
    228    */
    229   private static int stackDepthToOpenglDepth(int stackDepth) {
    230     return (MAX_DEPTH - stackDepth) * DEPTH_SCALE;
    231   }
    232 
    233   /**
    234    * A private constructor that forces users to use {@code createFromDepthRange}
    235    * to construct an instance of BlurStack.
    236    */
    237   private BlurStack() {}
    238 
    239   /**
    240    * Quantizes the depth range into MAX_DEPTH levels in inverse depth space, and
    241    * for each level, computes the blur disk radius.
    242    *
    243    * @param depthTransform an object that translates between floating depth and
    244    *        quantized depth.
    245    * @param frontFocalDepth front focal depth level
    246    * @param backFocalDepth back focal depth level
    247    * @param blurInfinity the amount of desired blur represented as the blur
    248    *        radius at infinity
    249    */
    250   private void computeDiskRadius(final DepthTransform depthTransform,
    251       int frontFocalDepth, int backFocalDepth, float blurInfinity) {
    252     int numLevels = MAX_DEPTH - MIN_DEPTH + 1;
    253     diskRadiusArray = new float[numLevels];
    254     float frontFocalDepth3D =
    255         depthTransform.reconstruct(stackDepthToOpenglDepth(frontFocalDepth));
    256     float backFocalDepth3D =
    257         depthTransform.reconstruct(stackDepthToOpenglDepth(backFocalDepth));
    258 
    259     // Computes the blur disk radius for each depth level.
    260     for (int depth = MIN_DEPTH; depth <= MAX_DEPTH; ++depth) {
    261       float depth3D =
    262           depthTransform.reconstruct(stackDepthToOpenglDepth(depth));
    263       float radius = 0;
    264       if (depth3D < frontFocalDepth3D) {
    265         radius = blurInfinity * (frontFocalDepth3D - depth3D) / depth3D;
    266       } else if (depth3D > backFocalDepth3D) {
    267         radius = blurInfinity * (depth3D - backFocalDepth3D) / depth3D;
    268       }
    269       diskRadiusArray[depth - MIN_DEPTH] = Math.min(radius, MAX_DISC_RADIUS);
    270     }
    271   }
    272 
    273   /**
    274    * Sets up {@code focusLayer} such that each layer contains only a single
    275    * depth, except that the focal layer contains frontFocalDepth and
    276    * backFocalDepth.
    277    *
    278    * <b> This function computes {@code layerInfo, focusLayer}.
    279    *
    280    * @param frontFocalDepth the front depth of focal layer.
    281    * @param backFocalDepth the back depth of focal layer.
    282    */
    283   private void generateOneLayerForEachDepth(int frontFocalDepth,
    284       int backFocalDepth) {
    285     int numLayers =
    286         MAX_DEPTH - MIN_DEPTH + 1 - (frontFocalDepth - backFocalDepth);
    287     layerInfo = new LayerInfo[numLayers];
    288 
    289     // Pushes single depth layers in front of the focal layer to layerInfo.
    290     int layer = 0;
    291     for (int depth = MAX_DEPTH; depth > frontFocalDepth; --depth, ++layer) {
    292       layerInfo[layer] = new LayerInfo(depth);
    293     }
    294 
    295     // Pushes focal layer to layerInfo.
    296     focusLayer = layer;
    297     layerInfo[layer] = new LayerInfo(frontFocalDepth, backFocalDepth);
    298     ++layer;
    299 
    300     // Pushes single depth layers behind the focal layer to layerInfo.
    301     for (int depth = backFocalDepth - 1; depth >= MIN_DEPTH; --depth, ++layer) {
    302       layerInfo[layer] = new LayerInfo(depth);
    303     }
    304   }
    305 
    306   /**
    307    * Sets up {@code focusLayer} such that within each layer, the blur radius
    308    * variation due to depth difference is no larger than
    309    * {@code diskRadiusInterval}.
    310    *
    311    * <b> This function computes {@code layerInfo, focusLayer}, assuming that
    312    * {@code diskRadius} have been properly initialized.
    313    *
    314    * @param frontFocalDepth the front depth of focal layer.
    315    * @param backFocalDepth the back depth of focal layer.
    316    * @diskRadiusInterval the max allowed blur disk radius difference within each
    317    *                     layer.
    318    */
    319   private void groupDepthLevelsIntoLayers(int frontFocalDepth,
    320       int backFocalDepth, float diskRadiusInterval) {
    321     // Groups depth levels behind the focal depth into several layers.
    322     // The blur radius difference in each layer is no larger than
    323     // diskRadiusInterval.
    324     ArrayList<LayerInfo> layerInfoBehindFocus =
    325         groupDepthLevelsBehindFocus(backFocalDepth, diskRadiusInterval);
    326 
    327     // Groups depth levels in front of the focal depth into several layers.
    328     // The blur radius difference in each layer is no larger than {@code
    329     // diskRadiusInterval}.
    330     ArrayList<LayerInfo> layerInfoInFrontOfFocus =
    331         groupDepthLevelsInFrontOfFocus(frontFocalDepth, diskRadiusInterval);
    332 
    333     // Merges the two groups of layers into one stack of layers, plus the focus
    334     // depth layer.
    335     int numLayers =
    336         layerInfoInFrontOfFocus.size() + 1 + layerInfoBehindFocus.size();
    337     layerInfo = new LayerInfo[numLayers];
    338     focusLayer = layerInfoInFrontOfFocus.size();
    339 
    340     // The merged layers is ordered from the front-most layer to the back-most
    341     // layer.
    342     for (int n = 0; n < numLayers; ++n) {
    343       if (n < layerInfoInFrontOfFocus.size()) {
    344         // Finds the corresponding layer index m in layerInfoInFrontOfFocus,
    345         // which is ordered from focal depth to front-most.
    346         int m = (layerInfoInFrontOfFocus.size() - 1) - n;
    347         layerInfo[n] = layerInfoInFrontOfFocus.get(m);
    348       } else if (n == layerInfoInFrontOfFocus.size()) {
    349         layerInfo[n] = new LayerInfo(frontFocalDepth, backFocalDepth);
    350       } else {
    351         // Finds the corresponding layer index m in layerInfoBehindFocus, which
    352         // is ordered from focal depth to back-most.
    353         int m = n - (layerInfoInFrontOfFocus.size() + 1);
    354         layerInfo[n] = layerInfoBehindFocus.get(m);
    355       }
    356     }
    357   }
    358 
    359   /**
    360    * Groups depth levels behind the focal depth into several layers. The blur
    361    * radius difference in each layer is no larger than
    362    * {@code diskRadiusInterval}.
    363    *
    364    * @param backFocalDepth the back depth of focal layer.
    365    * @param diskRadiusInterval max disk radius variation in each layer
    366    * @return layerInfo layering of depth levels behind the focal depth
    367    */
    368   private ArrayList<LayerInfo> groupDepthLevelsBehindFocus(int backFocalDepth,
    369       float diskRadiusInterval) {
    370     // Initializes the layerInfo array with maximum capacity needed.
    371     ArrayList<LayerInfo> layerInfo =
    372         new ArrayList<LayerInfo>(diskRadiusArray.length);
    373 
    374     if (backFocalDepth == MIN_DEPTH) {
    375       return layerInfo;
    376     }
    377 
    378     // At this point, focusDepth > minDepth.
    379     // Moves to the first depth behind the focus depth and initializes a layer.
    380     int d = backFocalDepth - 1;
    381     layerInfo.add(new LayerInfo(d));
    382     // Sets up the max radius threshold for the layer.
    383     float radiusThreshold = getDiskRadius(d) + diskRadiusInterval;
    384 
    385     // Expands the layer to include depth levels so long as the blur disk
    386     // radius within the layer is not larger than radiusThreshold.
    387     // Stops the expansion when current depth is already the minDepth.
    388     while (d > MIN_DEPTH) {
    389       // Moves to the next depth.
    390       d--;
    391       if (getDiskRadius(d) <= radiusThreshold) {
    392         // Expands the current layer by lowering its back depth.
    393         int numLayers = layerInfo.size();
    394         layerInfo.get(numLayers - 1).backDepth = d;
    395       } else {
    396         // Generates a new single-depth layer.
    397         // Expands it in the next iteration if necessary.
    398         layerInfo.add(new LayerInfo(d));
    399         radiusThreshold = getDiskRadius(d) + diskRadiusInterval;
    400       }
    401     }
    402     return layerInfo;
    403   }
    404 
    405   /**
    406    * Groups depth levels in front of the focal depth into several layers. The
    407    * blur radius difference in each layer is no larger than
    408    * {@code diskRadiusInterval}.
    409    *
    410    * @param frontFocalDepth the back depth of focal layer.
    411    * @param diskRadiusInterval max disk radius variation in each layer
    412    * @return layerInfo layering of depth levels behind the focal depth
    413    */
    414   private ArrayList<LayerInfo> groupDepthLevelsInFrontOfFocus(
    415       int frontFocalDepth, float diskRadiusInterval) {
    416     // Initializes the layerInfo array with maximum capacity needed.
    417     ArrayList<LayerInfo> layerInfo =
    418         new ArrayList<LayerInfo>(diskRadiusArray.length);
    419 
    420     if (frontFocalDepth == MAX_DEPTH) {
    421       return layerInfo;
    422     }
    423 
    424     // At this point, focusDepth < maxDepth.
    425     // Moves to the first depth in front of the focus depth and initializes a
    426     // layer.
    427     int d = frontFocalDepth + 1;
    428     layerInfo.add(new LayerInfo(d));
    429     // Sets up the max radius threshold for the layer.
    430     float radiusThreshold = getDiskRadius(d) + diskRadiusInterval;
    431 
    432     // Expands the layer to include depth levels so long as the blur disk
    433     // radius within the layer is not larger than radiusThreshold.
    434     // Stops the expansion when current depth is already the maxDepth.
    435     while (d < MAX_DEPTH) {
    436       // Moves to the next depth.
    437       d++;
    438       if (getDiskRadius(d) <= radiusThreshold) {
    439         // Expands the current layer by increasing its front depth.
    440         int numLayers = layerInfo.size();
    441         layerInfo.get(numLayers - 1).frontDepth = d;
    442       } else {
    443         // Generates a new single-depth layer.
    444         // Expands it in the next iteration if necessary.
    445         layerInfo.add(new LayerInfo(d));
    446         radiusThreshold = getDiskRadius(d) + diskRadiusInterval;
    447       }
    448     }
    449     return layerInfo;
    450   }
    451 }
    452