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