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