Home | History | Annotate | Download | only in params
      1 /*
      2  * Copyright (C) 2014 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 android.hardware.camera2.params;
     18 
     19 import static com.android.internal.util.Preconditions.*;
     20 import static android.hardware.camera2.params.RggbChannelVector.*;
     21 
     22 import android.hardware.camera2.CameraCharacteristics;
     23 import android.hardware.camera2.CaptureResult;
     24 import android.hardware.camera2.utils.HashCodeHelpers;
     25 
     26 import java.util.Arrays;
     27 
     28 /**
     29  * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
     30  *
     31  * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
     32  */
     33 public final class LensShadingMap {
     34 
     35     /**
     36      * The smallest gain factor in this map.
     37      *
     38      * <p>All values in this map will be at least this large.</p>
     39      */
     40     public static final float MINIMUM_GAIN_FACTOR = 1.0f;
     41 
     42     /**
     43      * Create a new immutable LensShadingMap instance.
     44      *
     45      * <p>The elements must be stored in a row-major order (fully packed).</p>
     46      *
     47      * <p>This constructor takes over the array; do not write to the array afterwards.</p>
     48      *
     49      * @param elements
     50      *          An array of elements whose length is
     51      *          {@code RggbChannelVector.COUNT * rows * columns}
     52      *
     53      * @throws IllegalArgumentException
     54      *            if the {@code elements} array length is invalid,
     55      *            if any of the subelems are not finite or less than {@value #MINIMUM_GAIN_FACTOR},
     56      *            or if rows or columns is not positive
     57      * @throws NullPointerException
     58      *            if {@code elements} is {@code null}
     59      *
     60      * @hide
     61      */
     62     public LensShadingMap(final float[] elements, final int rows, final int columns) {
     63 
     64         mRows = checkArgumentPositive(rows, "rows must be positive");
     65         mColumns = checkArgumentPositive(columns, "columns must be positive");
     66         mElements = checkNotNull(elements, "elements must not be null");
     67 
     68         if (elements.length != getGainFactorCount()) {
     69             throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
     70                     " length, received " + elements.length);
     71         }
     72 
     73         // Every element must be finite and >= 1.0f
     74         checkArrayElementsInRange(elements, MINIMUM_GAIN_FACTOR, Float.MAX_VALUE, "elements");
     75     }
     76 
     77     /**
     78      * Get the number of rows in this map.
     79      */
     80     public int getRowCount() {
     81         return mRows;
     82     }
     83 
     84     /**
     85      * Get the number of columns in this map.
     86      */
     87     public int getColumnCount() {
     88         return mColumns;
     89     }
     90 
     91     /**
     92      * Get the total number of gain factors in this map.
     93      *
     94      * <p>A single gain factor contains exactly one color channel.
     95      * Use with {@link #copyGainFactors} to allocate a large-enough array.</p>
     96      */
     97     public int getGainFactorCount() {
     98         return mRows * mColumns * COUNT;
     99     }
    100 
    101     /**
    102      * Get a single color channel gain factor from this lens shading map by its row and column.
    103      *
    104      * <p>The rows must be within the range [0, {@link #getRowCount}),
    105      * the column must be within the range [0, {@link #getColumnCount}),
    106      * and the color channel must be within the range [0, {@value RggbChannelVector#COUNT}).</p>
    107      *
    108      * <p>The channel order is {@code [R, Geven, Godd, B]}, where
    109      * {@code Geven} is the green channel for the even rows of a Bayer pattern, and
    110      * {@code Godd} is the odd rows.
    111      * </p>
    112      *
    113      * @param colorChannel color channel from {@code [R, Geven, Godd, B]}
    114      * @param column within the range [0, {@link #getColumnCount})
    115      * @param row within the range [0, {@link #getRowCount})
    116      *
    117      * @return a gain factor >= {@value #MINIMUM_GAIN_FACTOR}
    118      *
    119      * @throws IllegalArgumentException if any of the parameters was out of range
    120      *
    121      * @see #RED
    122      * @see #GREEN_EVEN
    123      * @see #GREEN_ODD
    124      * @see #BLUE
    125      * @see #getRowCount
    126      * @see #getColumnCount
    127      */
    128     public float getGainFactor(final int colorChannel, final int column, final int row) {
    129         if (colorChannel < 0 || colorChannel > COUNT) {
    130             throw new IllegalArgumentException("colorChannel out of range");
    131         } else if (column < 0 || column >= mColumns) {
    132             throw new IllegalArgumentException("column out of range");
    133         } else if (row < 0 || row >= mRows) {
    134             throw new IllegalArgumentException("row out of range");
    135         }
    136 
    137         return mElements[colorChannel + (row * mColumns +  column) * COUNT ];
    138     }
    139 
    140     /**
    141      * Get a gain factor vector from this lens shading map by its row and column.
    142      *
    143      * <p>The rows must be within the range [0, {@link #getRowCount}),
    144      * the column must be within the range [0, {@link #getColumnCount}).</p>
    145      *
    146      * @param column within the range [0, {@link #getColumnCount})
    147      * @param row within the range [0, {@link #getRowCount})
    148      *
    149      * @return an {@link RggbChannelVector} where each gain factor >= {@value #MINIMUM_GAIN_FACTOR}
    150      *
    151      * @throws IllegalArgumentException if any of the parameters was out of range
    152      *
    153      * @see #getRowCount
    154      * @see #getColumnCount
    155      */
    156     public RggbChannelVector getGainFactorVector(final int column, final int row) {
    157         if (column < 0 || column >= mColumns) {
    158             throw new IllegalArgumentException("column out of range");
    159         } else if (row < 0 || row >= mRows) {
    160             throw new IllegalArgumentException("row out of range");
    161         }
    162 
    163         final int offset = (row * mColumns +  column) * COUNT;
    164 
    165         final float red =
    166                 mElements[RED + offset];
    167         final float greenEven =
    168                 mElements[GREEN_EVEN + offset];
    169         final float greenOdd =
    170                 mElements[GREEN_ODD + offset];
    171         final float blue =
    172                 mElements[BLUE + offset];
    173 
    174         return new RggbChannelVector(red, greenEven, greenOdd, blue);
    175     }
    176 
    177     /**
    178      * Copy all gain factors in row-major order from this lens shading map into the destination.
    179      *
    180      * <p>Each gain factor will be >= {@link #MINIMUM_GAIN_FACTOR}.</p>
    181      *
    182      * @param destination
    183      *          an array big enough to hold at least {@link RggbChannelVector#COUNT}
    184      *          elements after the {@code offset}
    185      * @param offset
    186      *          a non-negative offset into the array
    187      * @throws NullPointerException
    188      *          If {@code destination} was {@code null}
    189      * @throws IllegalArgumentException
    190      *          If offset was negative
    191      * @throws ArrayIndexOutOfBoundsException
    192      *          If there's not enough room to write the elements at the specified destination and
    193      *          offset.
    194      *
    195      * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
    196      */
    197     public void copyGainFactors(final float[] destination, final int offset) {
    198         checkArgumentNonnegative(offset, "offset must not be negative");
    199         checkNotNull(destination, "destination must not be null");
    200         if (destination.length + offset < getGainFactorCount()) {
    201             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
    202         }
    203 
    204         System.arraycopy(mElements, /*srcPos*/0, destination, offset, getGainFactorCount());
    205     }
    206 
    207     /**
    208      * Check if this LensShadingMap is equal to another LensShadingMap.
    209      *
    210      * <p>Two lens shading maps are equal if and only if they have the same rows/columns,
    211      * and all of their elements are {@link Object#equals equal}.</p>
    212      *
    213      * @return {@code true} if the objects were equal, {@code false} otherwise
    214      */
    215     @Override
    216     public boolean equals(final Object obj) {
    217         if (obj == null) {
    218             return false;
    219         }
    220         if (this == obj) {
    221             return true;
    222         }
    223         if (obj instanceof LensShadingMap) {
    224             final LensShadingMap other = (LensShadingMap) obj;
    225             return mRows == other.mRows
    226                     && mColumns == other.mColumns
    227                     && Arrays.equals(mElements, other.mElements);
    228         }
    229         return false;
    230     }
    231 
    232     /**
    233      * {@inheritDoc}
    234      */
    235     @Override
    236     public int hashCode() {
    237         int elemsHash = HashCodeHelpers.hashCode(mElements);
    238         return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
    239     }
    240 
    241 
    242     private final int mRows;
    243     private final int mColumns;
    244     private final float[] mElements;
    245 }
    246