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