298 lines
11 KiB
Java
298 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.hardware.camera2.params;
|
|
|
|
import static android.hardware.camera2.params.RggbChannelVector.BLUE;
|
|
import static android.hardware.camera2.params.RggbChannelVector.COUNT;
|
|
import static android.hardware.camera2.params.RggbChannelVector.GREEN_EVEN;
|
|
import static android.hardware.camera2.params.RggbChannelVector.GREEN_ODD;
|
|
import static android.hardware.camera2.params.RggbChannelVector.RED;
|
|
|
|
import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
|
|
import static com.android.internal.util.Preconditions.checkArgumentPositive;
|
|
import static com.android.internal.util.Preconditions.checkArrayElementsInRange;
|
|
|
|
import android.hardware.camera2.CaptureResult;
|
|
import android.hardware.camera2.utils.HashCodeHelpers;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
|
|
*
|
|
* @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
|
|
*/
|
|
public final class LensShadingMap {
|
|
|
|
/**
|
|
* The smallest gain factor in this map.
|
|
*
|
|
* <p>All values in this map will be at least this large.</p>
|
|
*/
|
|
public static final float MINIMUM_GAIN_FACTOR = 1.0f;
|
|
|
|
/**
|
|
* Create a new immutable LensShadingMap instance.
|
|
*
|
|
* <p>The elements must be stored in a row-major order (fully packed).</p>
|
|
*
|
|
* <p>This constructor takes over the array; do not write to the array afterwards.</p>
|
|
*
|
|
* @param elements
|
|
* An array of elements whose length is
|
|
* {@code RggbChannelVector.COUNT * rows * columns}
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* if the {@code elements} array length is invalid,
|
|
* if any of the subelems are not finite or less than {@value #MINIMUM_GAIN_FACTOR},
|
|
* or if rows or columns is not positive
|
|
* @throws NullPointerException
|
|
* if {@code elements} is {@code null}
|
|
*
|
|
* @hide
|
|
*/
|
|
public LensShadingMap(final float[] elements, final int rows, final int columns) {
|
|
|
|
mRows = checkArgumentPositive(rows, "rows must be positive");
|
|
mColumns = checkArgumentPositive(columns, "columns must be positive");
|
|
mElements = Objects.requireNonNull(elements, "elements must not be null");
|
|
|
|
if (elements.length != getGainFactorCount()) {
|
|
throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
|
|
" length, received " + elements.length);
|
|
}
|
|
|
|
// Every element must be finite and >= 1.0f
|
|
checkArrayElementsInRange(elements, MINIMUM_GAIN_FACTOR, Float.MAX_VALUE, "elements");
|
|
}
|
|
|
|
/**
|
|
* Get the number of rows in this map.
|
|
*/
|
|
public int getRowCount() {
|
|
return mRows;
|
|
}
|
|
|
|
/**
|
|
* Get the number of columns in this map.
|
|
*/
|
|
public int getColumnCount() {
|
|
return mColumns;
|
|
}
|
|
|
|
/**
|
|
* Get the total number of gain factors in this map.
|
|
*
|
|
* <p>A single gain factor contains exactly one color channel.
|
|
* Use with {@link #copyGainFactors} to allocate a large-enough array.</p>
|
|
*/
|
|
public int getGainFactorCount() {
|
|
return mRows * mColumns * COUNT;
|
|
}
|
|
|
|
/**
|
|
* Get a single color channel gain factor from this lens shading map by its row and column.
|
|
*
|
|
* <p>The rows must be within the range [0, {@link #getRowCount}),
|
|
* the column must be within the range [0, {@link #getColumnCount}),
|
|
* and the color channel must be within the range [0, {@value RggbChannelVector#COUNT}).</p>
|
|
*
|
|
* <p>The channel order is {@code [R, Geven, Godd, B]}, where
|
|
* {@code Geven} is the green channel for the even rows of a Bayer pattern, and
|
|
* {@code Godd} is the odd rows.
|
|
* </p>
|
|
*
|
|
* @param colorChannel color channel from {@code [R, Geven, Godd, B]}
|
|
* @param column within the range [0, {@link #getColumnCount})
|
|
* @param row within the range [0, {@link #getRowCount})
|
|
*
|
|
* @return a gain factor >= {@value #MINIMUM_GAIN_FACTOR}
|
|
*
|
|
* @throws IllegalArgumentException if any of the parameters was out of range
|
|
*
|
|
* @see RggbChannelVector#RED
|
|
* @see RggbChannelVector#GREEN_EVEN
|
|
* @see RggbChannelVector#GREEN_ODD
|
|
* @see RggbChannelVector#BLUE
|
|
* @see #getRowCount
|
|
* @see #getColumnCount
|
|
*/
|
|
public float getGainFactor(final int colorChannel, final int column, final int row) {
|
|
if (colorChannel < 0 || colorChannel > COUNT) {
|
|
throw new IllegalArgumentException("colorChannel out of range");
|
|
} else if (column < 0 || column >= mColumns) {
|
|
throw new IllegalArgumentException("column out of range");
|
|
} else if (row < 0 || row >= mRows) {
|
|
throw new IllegalArgumentException("row out of range");
|
|
}
|
|
|
|
return mElements[colorChannel + (row * mColumns + column) * COUNT ];
|
|
}
|
|
|
|
/**
|
|
* Get a gain factor vector from this lens shading map by its row and column.
|
|
*
|
|
* <p>The rows must be within the range [0, {@link #getRowCount}),
|
|
* the column must be within the range [0, {@link #getColumnCount}).</p>
|
|
*
|
|
* @param column within the range [0, {@link #getColumnCount})
|
|
* @param row within the range [0, {@link #getRowCount})
|
|
*
|
|
* @return an {@link RggbChannelVector} where each gain factor >= {@value #MINIMUM_GAIN_FACTOR}
|
|
*
|
|
* @throws IllegalArgumentException if any of the parameters was out of range
|
|
*
|
|
* @see #getRowCount
|
|
* @see #getColumnCount
|
|
*/
|
|
public RggbChannelVector getGainFactorVector(final int column, final int row) {
|
|
if (column < 0 || column >= mColumns) {
|
|
throw new IllegalArgumentException("column out of range");
|
|
} else if (row < 0 || row >= mRows) {
|
|
throw new IllegalArgumentException("row out of range");
|
|
}
|
|
|
|
final int offset = (row * mColumns + column) * COUNT;
|
|
|
|
final float red =
|
|
mElements[RED + offset];
|
|
final float greenEven =
|
|
mElements[GREEN_EVEN + offset];
|
|
final float greenOdd =
|
|
mElements[GREEN_ODD + offset];
|
|
final float blue =
|
|
mElements[BLUE + offset];
|
|
|
|
return new RggbChannelVector(red, greenEven, greenOdd, blue);
|
|
}
|
|
|
|
/**
|
|
* Copy all gain factors in row-major order from this lens shading map into the destination.
|
|
*
|
|
* <p>Each gain factor will be >= {@link #MINIMUM_GAIN_FACTOR}.</p>
|
|
*
|
|
* @param destination
|
|
* an array big enough to hold at least {@link RggbChannelVector#COUNT}
|
|
* elements after the {@code offset}
|
|
* @param offset
|
|
* a non-negative offset into the array
|
|
* @throws NullPointerException
|
|
* If {@code destination} was {@code null}
|
|
* @throws IllegalArgumentException
|
|
* If offset was negative
|
|
* @throws ArrayIndexOutOfBoundsException
|
|
* If there's not enough room to write the elements at the specified destination and
|
|
* offset.
|
|
*
|
|
* @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
|
|
*/
|
|
public void copyGainFactors(final float[] destination, final int offset) {
|
|
checkArgumentNonnegative(offset, "offset must not be negative");
|
|
Objects.requireNonNull(destination, "destination must not be null");
|
|
if (destination.length + offset < getGainFactorCount()) {
|
|
throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
|
|
}
|
|
|
|
System.arraycopy(mElements, /*srcPos*/0, destination, offset, getGainFactorCount());
|
|
}
|
|
|
|
/**
|
|
* Check if this LensShadingMap is equal to another LensShadingMap.
|
|
*
|
|
* <p>Two lens shading maps are equal if and only if they have the same rows/columns,
|
|
* and all of their elements are {@link Object#equals equal}.</p>
|
|
*
|
|
* @return {@code true} if the objects were equal, {@code false} otherwise
|
|
*/
|
|
@Override
|
|
public boolean equals(final Object obj) {
|
|
if (obj == null) {
|
|
return false;
|
|
}
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj instanceof LensShadingMap) {
|
|
final LensShadingMap other = (LensShadingMap) obj;
|
|
return mRows == other.mRows
|
|
&& mColumns == other.mColumns
|
|
&& Arrays.equals(mElements, other.mElements);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
int elemsHash = HashCodeHelpers.hashCode(mElements);
|
|
return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
|
|
}
|
|
|
|
/**
|
|
* Return the LensShadingMap as a string representation.
|
|
*
|
|
* <p> {@code "LensShadingMap{R:([%f, %f, ... %f], ... [%f, %f, ... %f]), G_even:([%f, %f, ...
|
|
* %f], ... [%f, %f, ... %f]), G_odd:([%f, %f, ... %f], ... [%f, %f, ... %f]), B:([%f, %f, ...
|
|
* %f], ... [%f, %f, ... %f])}"},
|
|
* where each {@code %f} represents one gain factor and each {@code [%f, %f, ... %f]} represents
|
|
* a row of the lens shading map</p>
|
|
*
|
|
* @return string representation of {@link LensShadingMap}
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder str = new StringBuilder();
|
|
str.append("LensShadingMap{");
|
|
|
|
final String channelPrefix[] = {"R:(", "G_even:(", "G_odd:(", "B:("};
|
|
|
|
for (int ch = 0; ch < COUNT; ch++) {
|
|
str.append(channelPrefix[ch]);
|
|
|
|
for (int r = 0; r < mRows; r++) {
|
|
str.append("[");
|
|
for (int c = 0; c < mColumns; c++) {
|
|
float gain = getGainFactor(ch, c, r);
|
|
str.append(gain);
|
|
if (c < mColumns - 1) {
|
|
str.append(", ");
|
|
}
|
|
}
|
|
str.append("]");
|
|
if (r < mRows - 1) {
|
|
str.append(", ");
|
|
}
|
|
}
|
|
|
|
str.append(")");
|
|
if (ch < COUNT - 1) {
|
|
str.append(", ");
|
|
}
|
|
}
|
|
|
|
str.append("}");
|
|
return str.toString();
|
|
}
|
|
|
|
private final int mRows;
|
|
private final int mColumns;
|
|
private final float[] mElements;
|
|
}
|