14cead8034aab0e20e402baee87cbe9129db00192Stephen Hinespackage com.android.rs.refocus; 2de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 3de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.content.ContentResolver; 4de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.content.Context; 5de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.Bitmap; 6de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.BitmapFactory; 7de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.graphics.Color; 8de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.net.Uri; 9de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport android.util.Log; 10de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 11de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport java.io.FileNotFoundException; 12de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangimport java.io.IOException; 13de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 14de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang/** 15de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * An RGBZ image, where Z stands for depth, i.e. a color+depth image. 16de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The RGBZ always has a preview image, which represents the latest rendering of the RGBZ. 17de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The preview is encoded as the normal jpeg content for client compatibility, 18de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * while the color channel and depth channels are encoded as XMP data. 19de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * The class supports lazy initialization where the XMP meta data is loaded only when first 20de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * accessed. 21de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * 22de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @author chernand@google.com (Carlos Hernandez) 23de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 24de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wangpublic class RGBZ { 25de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public static final String TAG = "RGBZ"; 26de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 27de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap bitmap; 28de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap preview; 29de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap depthBitmap; 30de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private DepthTransform depthTransform; 31de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private DepthImage depthImage; 32de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 33de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 34de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * Creates an RGBZ from a content uri. 35de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * 36de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @param uri The uri name of the RGBZ 37de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @throws FileNotFoundException if the RGBZ could not be read 38de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 39de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public RGBZ(Uri uri, ContentResolver contentResolver, Context context) throws IOException { 40de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uri)); 41de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (preview == null) { 42de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang throw new FileNotFoundException(uri.toString()); 43de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 44de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang this.depthImage = new DepthImage(context, uri); 45de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang this.depthBitmap = depthImage.getDepthBitmap(); 46de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang this.bitmap = setAlphaChannel(preview, this.depthBitmap); 47de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang this.depthTransform = depthImage.getDepthTransform(); 48de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 49de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 50de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 51de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return Whether the RGBZ has a depth channel 52de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 53de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public boolean hasDepthmap() { 54de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return depthTransform != null; 55de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 56de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 57de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 58de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return The color+depth {@code Bitmap} 59de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 60de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public Bitmap getBitmap() { 61de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap; 62de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 63de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 64de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 65de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return The depthmap component of this RGBZ 66de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 67de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public DepthTransform getDepthTransform() { 68de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return depthTransform; 69de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 70de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 71de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getFocusDepth() { 72de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getFocalDistance(); 73de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 74de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 75de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getDepthOfField() { 76de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getDepthOfField(); 77de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 78de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 79de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public double getBlurInfinity() { 80de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return this.depthImage.getBlurAtInfinity(); 81de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 82de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 83de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 84de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the width of this {@code RGBZ} 85de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 86de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public int getWidth() { 87de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap.getWidth(); 88de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 89de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 90de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 91de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the height of this {@code RGBZ} 92de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 93de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public int getHeight() { 94de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap.getHeight(); 95de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 96de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 97de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 98de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * @return the depth value of the given pixel 99de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 100de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 101de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public float getDepth(int x, int y) { 102de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (!hasDepthmap()) { 103de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return 0.0f; 104de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 105de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (x < 0 || x > depthBitmap.getWidth() || 106de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang y < 0 || y > depthBitmap.getHeight()) { 107de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang Log.e("RGBZ getDepth", "index out of bound"); 108de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return 0; 109de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 110de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return getDepthTransform().reconstruct(Color.blue(depthBitmap.getPixel(x, y))); 111de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 112de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 113de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang /** 114de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang * Sets the depthmap as the alpha channel of the {@code Bitmap}. 115de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang */ 116de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang public Bitmap setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap) { 117de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang if (bitmap == null) { 118de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return bitmap; 119de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 120de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, true); 121de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang // set the alpha channel of depthBitmap to alpha of bitmap 122de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang result = setAlphaChannelFromBitmap(depthBitmap, bitmap, result); 123de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return result; 124de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 125de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 126de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang private Bitmap setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest) { 127de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int w = orig.getWidth(); 128de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int h = orig.getHeight(); 129de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int[] orig_data = new int[w*h]; 130de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int[] depth_data = new int[w*h]; 131de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 132de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang orig.getPixels(orig_data, 0, w, 0, 0, w, h); 133de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang depth.getPixels(depth_data, 0, w, 0, 0, w, h); 134de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang for (int i = 0; i < orig_data.length; i++) { 135de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int v = orig_data[i] & 0x00FFFFFF; 136de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang int temp = (depth_data[i] & 0x000000FF) << 24; 137de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang v = v | temp; 138de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang orig_data[i] = v; 139de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 140de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang dest.setPixels(orig_data, 0, w, 0, 0, w, h); 141de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang return dest; 142de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang } 143de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang} 144de2f182fdb522689e05280e449a39ec2c1b53e1fCindy Wang 145