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