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 getMaxDiskRadius()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 */ getDiskRadius(int depth)103 public float getDiskRadius(int depth) { 104 return diskRadiusArray[depth - MIN_DEPTH]; 105 } 106 getNumLayers()107 public int getNumLayers() { 108 return layerInfo.length; 109 } 110 getLayerInfo(int layer)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 */ getNumDepths(int layer)121 public int getNumDepths(int layer) { 122 return layerInfo[layer].frontDepth - layerInfo[layer].backDepth + 1; 123 } 124 getFocusLayer()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 */ getDepth(int layer, int relativeDepthInLayer)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 */ createFromDepthTransform( final DepthTransform depthTransform, float focusDepth3D, float depthOfField, float blurInfinity, int numBlendingLayers)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 toString()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 */ openglDepthToStackDepth(int openglDepth)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 */ stackDepthToOpenglDepth(int stackDepth)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 */ BlurStack()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 */ computeDiskRadius(final DepthTransform depthTransform, int frontFocalDepth, int backFocalDepth, float blurInfinity)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 */ generateOneLayerForEachDepth(int frontFocalDepth, int backFocalDepth)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 */ groupDepthLevelsIntoLayers(int frontFocalDepth, int backFocalDepth, float diskRadiusInterval)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 */ groupDepthLevelsBehindFocus(int backFocalDepth, float diskRadiusInterval)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 */ groupDepthLevelsInFrontOfFocus( int frontFocalDepth, float diskRadiusInterval)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