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 com.android.rs.refocus;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.BitmapFactory;
22 import android.net.Uri;
23 import com.android.rs.refocus.image.RangeInverseDepthTransform;
24 import com.android.rs.refocus.image.RangeLinearDepthTransform;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 
29 public class DepthImage {
30     private final String mFormat;
31     private final double mFar;
32     private final double mNear;
33     private final Bitmap mDepthBitmap;
34     private final double mBlurAtInfinity;
35     private final double mFocalDistance;
36     private final double mDepthOfField;
37     private final double mFocalPointX;
38     private final double mFocalPointY;
39     private final DepthTransform mDepthTransform;
40 
DepthImage(String format, double far, double near, Bitmap depthBitmap, double blurAtInfinity, double focalDistance, double depthOfField, double focalPointX, double focalPointY, DepthTransform depthTransform)41     public DepthImage(String format, double far, double near,
42                       Bitmap depthBitmap, double blurAtInfinity,
43                       double focalDistance, double depthOfField,
44                       double focalPointX, double focalPointY,
45                       DepthTransform depthTransform) {
46         mFormat = format;
47         mFar = far;
48         mNear = near;
49         mDepthBitmap = depthBitmap;
50         mBlurAtInfinity = blurAtInfinity;
51         mFocalDistance = focalDistance;
52         mDepthOfField = depthOfField;
53         mFocalPointX = focalPointX;
54         mFocalPointY = focalPointY;
55         mDepthTransform = depthTransform;
56     }
57 
createFromXMPMetadata(Context context, Uri image)58     public static DepthImage createFromXMPMetadata(Context context, Uri image)
59             throws IOException {
60         InputStream input = context.getContentResolver().openInputStream(image);
61         XmpDepthDecode decode = new XmpDepthDecode(input);
62         return new DepthImage(decode.getFormat(), decode.getFar(),
63                               decode.getNear(), decode.getDepthBitmap(),
64                               decode.getBlurAtInfinity(),
65                               decode.getFocalDistance(),
66                               decode.getDepthOfField(),
67                               decode.getFocalPointX(),
68                               decode.getFocalPointY(),
69                               decode.getDepthTransform());
70     }
71 
createFromDepthmap(Context context, Uri uriDepthmap)72     public static DepthImage createFromDepthmap(Context context, Uri uriDepthmap)
73             throws IOException {
74         Bitmap bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uriDepthmap));
75         if (bitmap == null) {
76             throw new FileNotFoundException(uriDepthmap.toString());
77         }
78 
79         double near = 12.0;
80         double far = 120.0;
81         DepthTransform transform = new RangeInverseDepthTransform((float)near, (float)far);
82         return new DepthImage(RangeInverseDepthTransform.FORMAT,
83                               far,
84                               near,
85                               bitmap, // depthmap
86                               5.0,    // blur at ininity
87                               15.0,   // focal distance
88                               0.1,    // depth of field
89                               0.5,    // x of focal point
90                               0.5,    // y of focla point
91                               transform);
92     }
93 
94     private static class MinMax {
95         public float min;
96         public float max;
97 
MinMax(float min, float max)98         public MinMax(float min, float max) {
99             this.min = min;
100             this.max = max;
101         }
102 
create(float min, float max)103         public static MinMax create(float min, float max) {
104             return new MinMax(min, max);
105         }
106     }
107 
findMinAndMax(final float[] array)108     private static MinMax findMinAndMax(final float[] array) {
109         float min = array[0];
110         float max = min;
111         for (int i = 1; i < array.length; i++) {
112             final float x = array[i];
113             if (x < min) {
114                 min = x;
115             } else if (x > max) {
116                 max = x;
117             }
118         }
119         return MinMax.create(min, max);
120     }
121 
createFromPFM(Context context, Uri uriPFM)122     public static DepthImage createFromPFM(Context context, Uri uriPFM)
123             throws IOException {
124         PortableFloatMap pfm = new PortableFloatMap(context.getContentResolver().openInputStream(uriPFM));
125 
126         final float[] floatPixels = pfm.getPixelArray();
127         int[] intPixels = new int[floatPixels.length];
128         final MinMax minMax = findMinAndMax(floatPixels);
129         final float near = minMax.min;
130         final float far  = minMax.max;
131         DepthTransform transform = new RangeInverseDepthTransform(near, far);
132 
133 /*
134         android.util.Log.v("DepthImage", "near = " + String.format("%g", near));
135         android.util.Log.v("DepthImage", "far  = " + String.format("%g", far));
136 */
137         int width = pfm.getWidth();
138         int height = pfm.getHeight();
139 
140         for (int i = 0; i < intPixels.length; i++) {
141             int value = transform.quantize(floatPixels[i]) & 0xFF;
142             intPixels[i] = value | (value << 8) | (value << 16) | (0xFF << 24);
143 /*
144             if (i >= intPixels.length - width) {
145                 android.util.Log.v("DepthImage", "float pixel " + i + ":" + String.format("%g", floatPixels[i]));
146                 android.util.Log.v("DepthImage", "int pixel   " + i + ":" + String.format("0x%02X", intPixels[i]));
147             }
148 */
149         }
150 
151         Bitmap bitmap = Bitmap.createBitmap(intPixels, width, height, Bitmap.Config.ARGB_8888);
152 
153         // MediaStoreSaver.savePNG(bitmap, "depthmap", "balls", context);
154 
155         return new DepthImage(RangeInverseDepthTransform.FORMAT,
156                               far,
157                               near,
158                               bitmap, // depthmap
159                               400.0,  // blur at ininity
160                               //15.0,  // blur at ininity
161                               19.6,   // focal distance
162                               //near+(far-near)*0.2,   // focal distance
163                               //5.0,    // flocal distance
164                               0.005,    // depth of field
165                               0.4,    // x of focal point
166                               0.4,    // y of focal point
167                               transform);
168     }
169 
getDepthBitmap()170     public Bitmap getDepthBitmap() {
171         return mDepthBitmap;
172     }
173 
getDepthTransform()174     public DepthTransform getDepthTransform() { return mDepthTransform; }
175 
getFormat()176     public String getFormat() {
177         return mFormat;
178     }
179 
getFar()180     public double getFar() {
181         return mFar;
182     }
183 
getNear()184     public double getNear() {
185         return mNear;
186     }
187 
getBlurAtInfinity()188     public double getBlurAtInfinity() {
189         return mBlurAtInfinity;
190     }
191 
getFocalDistance()192     public double getFocalDistance() {
193         return mFocalDistance;
194     }
195 
getDepthOfField()196     public double getDepthOfField() {return mDepthOfField; }
197 
getFocalPointX()198     public double getFocalPointX() {
199         return mFocalPointX;
200     }
201 
getFocalPointY()202     public double getFocalPointY() {
203         return mFocalPointY;
204     }
205 }
206 
207