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