1fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni/* 2fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * Copyright (C) 2015 The Android Open Source Project 3fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * 4fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * Licensed under the Apache License, Version 2.0 (the "License"); 5fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * you may not use this file except in compliance with the License. 6fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * You may obtain a copy of the License at 7fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * 8fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * http://www.apache.org/licenses/LICENSE-2.0 9fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * 10fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * Unless required by applicable law or agreed to in writing, software 11fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * distributed under the License is distributed on an "AS IS" BASIS, 12fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * See the License for the specific language governing permissions and 14fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * limitations under the License. 15fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni */ 16fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 174cead8034aab0e20e402baee87cbe9129db00192Stephen Hinespackage com.android.rs.refocus; 18de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 19de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.content.ContentResolver; 20de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.content.Context; 21de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.Bitmap; 22de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.BitmapFactory; 23de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.Color; 24de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.net.Uri; 25de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.util.Log; 26fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Niimport com.android.rs.refocus.image.RangeInverseDepthTransform; 27de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport java.io.FileNotFoundException; 28de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport java.io.IOException; 29de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 30de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang/** 31de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * An RGBZ image, where Z stands for depth, i.e. a color+depth image. 32de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The RGBZ always has a preview image, which represents the latest rendering of the RGBZ. 33de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The preview is encoded as the normal jpeg content for client compatibility, 34de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * while the color channel and depth channels are encoded as XMP data. 35de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The class supports lazy initialization where the XMP meta data is loaded only when first 36de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * accessed. 37de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 38de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangpublic class RGBZ { 39de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public static final String TAG = "RGBZ"; 40de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 41de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap bitmap; 42de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap preview; 43de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap depthBitmap; 44de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private DepthTransform depthTransform; 45de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private DepthImage depthImage; 46de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 47de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 48de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * Creates an RGBZ from a content uri. 49de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * 50de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @param uri The uri name of the RGBZ 51de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @throws FileNotFoundException if the RGBZ could not be read 52de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 53de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public RGBZ(Uri uri, ContentResolver contentResolver, Context context) throws IOException { 54de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uri)); 55de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (preview == null) { 56de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang throw new FileNotFoundException(uri.toString()); 57de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 58fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthImage = DepthImage.createFromXMPMetadata(context, uri); 59fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthBitmap = depthImage.getDepthBitmap(); 60fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni //MediaStoreSaver.savePNG(depthBitmap, "depthmap", "depthmap", context); 61fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni bitmap = setAlphaChannel(preview, depthBitmap); 62fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthTransform = depthImage.getDepthTransform(); 63fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 64fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 65fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni /** 66fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * Creates an RGBZ from uris to an image and a depthmap. 67fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * 68fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * @param uriImage The uri name of the image 69fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * @param uriDepthmap The uri name of the depthmap 70fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni * @throws FileNotFoundException if the RGBZ could not be read 71fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni */ 72fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni public RGBZ(Uri uriImage, Uri uriDepthmap, ContentResolver contentResolver, 73fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni Context context) throws IOException { 74fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage)); 75fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni if (preview == null) { 76fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni throw new FileNotFoundException(uriImage.toString()); 77fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 78fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthImage = DepthImage.createFromDepthmap(context, uriDepthmap); 79fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthBitmap = depthImage.getDepthBitmap(); 80fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni bitmap = setAlphaChannel(preview, depthBitmap); 81fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthTransform = depthImage.getDepthTransform(); 82de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 83de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 84fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 85fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni public RGBZ(Bitmap image, DepthImage depthImage) { 86fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni preview = image; 87fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni this.depthImage = depthImage; 88fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthBitmap = depthImage.getDepthBitmap(); 89fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni bitmap = setAlphaChannel(preview, depthBitmap); 90fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni depthTransform = depthImage.getDepthTransform(); 91fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 92fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 93fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni public static RGBZ createFromBitmapDepthmap(Uri uriImage, Uri uriDepthmap, 94fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni ContentResolver contentResolver, Context context) 95fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni throws IOException { 96fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni Bitmap image = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage)); 97fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni if (image == null) { 98fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni throw new FileNotFoundException(uriImage.toString()); 99fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 100fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni DepthImage depthImage = DepthImage.createFromDepthmap(context, uriDepthmap); 101fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni return new RGBZ(image, depthImage); 102fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 103fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 104fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni public static RGBZ createFromPFMDepthmap(Uri uriImage, Uri uriDepthmap, 105fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni ContentResolver contentResolver, Context context) 106fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni throws IOException { 107fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni Bitmap image = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage)); 108fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni if (image == null) { 109fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni throw new FileNotFoundException(uriImage.toString()); 110fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 111fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni DepthImage depthImage = DepthImage.createFromPFM(context, uriDepthmap); 112fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni MediaStoreSaver.savePNG(depthImage.getDepthBitmap(), "depthmap", 113fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni "depthmap", context); 114fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni return new RGBZ(image, depthImage); 115fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni } 116fb2af6b101911d7abf65a519704cdaebb0cae6fdYang Ni 117de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 118de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return Whether the RGBZ has a depth channel 119de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 120de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public boolean hasDepthmap() { 121de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return depthTransform != null; 122de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 123de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 124de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 125de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return The color+depth {@code Bitmap} 126de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 127de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public Bitmap getBitmap() { 128de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap; 129de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 130de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 131de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 132de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return The depthmap component of this RGBZ 133de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 134de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public DepthTransform getDepthTransform() { 135de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return depthTransform; 136de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 137de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 138de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getFocusDepth() { 139de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getFocalDistance(); 140de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 141de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 142de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getDepthOfField() { 143de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getDepthOfField(); 144de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 145de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 146de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getBlurInfinity() { 147de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getBlurAtInfinity(); 148de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 149de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 150de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 151de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the width of this {@code RGBZ} 152de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 153de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public int getWidth() { 154de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap.getWidth(); 155de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 156de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 157de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 158de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the height of this {@code RGBZ} 159de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 160de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public int getHeight() { 161de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap.getHeight(); 162de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 163de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 164de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 165de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the depth value of the given pixel 166de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 167de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 168de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public float getDepth(int x, int y) { 169de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (!hasDepthmap()) { 170de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return 0.0f; 171de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 172de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (x < 0 || x > depthBitmap.getWidth() || 173de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang y < 0 || y > depthBitmap.getHeight()) { 174de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang Log.e("RGBZ getDepth", "index out of bound"); 175de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return 0; 176de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 177de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return getDepthTransform().reconstruct(Color.blue(depthBitmap.getPixel(x, y))); 178de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 179de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 180de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 181de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * Sets the depthmap as the alpha channel of the {@code Bitmap}. 182de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 183de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public Bitmap setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap) { 184de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (bitmap == null) { 185de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap; 186de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 187de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, true); 188de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang // set the alpha channel of depthBitmap to alpha of bitmap 189de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang result = setAlphaChannelFromBitmap(depthBitmap, bitmap, result); 190de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return result; 191de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 192de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 193de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest) { 194de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int w = orig.getWidth(); 195de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int h = orig.getHeight(); 196de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int[] orig_data = new int[w*h]; 197de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int[] depth_data = new int[w*h]; 198de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 199de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang orig.getPixels(orig_data, 0, w, 0, 0, w, h); 200de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang depth.getPixels(depth_data, 0, w, 0, 0, w, h); 201de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang for (int i = 0; i < orig_data.length; i++) { 202de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int v = orig_data[i] & 0x00FFFFFF; 203de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int temp = (depth_data[i] & 0x000000FF) << 24; 204de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang v = v | temp; 205de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang orig_data[i] = v; 206de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 207de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang dest.setPixels(orig_data, 0, w, 0, 0, w, h); 208de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return dest; 209de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 210de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang} 211de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 212