TonemapCurvepublic final class TonemapCurve extends Object Immutable class for describing a {@code 2 x M x 3} tonemap curve of floats.
This defines red, green, and blue curves that the {@link CameraDevice} will
use as the tonemapping/contrast/gamma curve when {@link CaptureRequest#TONEMAP_MODE} is
set to {@link CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE}.
The total number of points {@code (Pin, Pout)} for each color channel can be no more than
{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS}.
The coordinate system for each point is within the inclusive range
[{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}]. |
Fields Summary |
---|
public static final float | LEVEL_BLACKLower bound tonemap value corresponding to pure black for a single color channel. | public static final float | LEVEL_WHITEUpper bound tonemap value corresponding to a pure white for a single color channel. | public static final int | POINT_SIZENumber of elements in a {@code (Pin, Pout)} point; | public static final int | CHANNEL_REDIndex of the red color channel curve. | public static final int | CHANNEL_GREENIndex of the green color channel curve. | public static final int | CHANNEL_BLUEIndex of the blue color channel curve. | private static final int | OFFSET_POINT_IN | private static final int | OFFSET_POINT_OUT | private static final int | TONEMAP_MIN_CURVE_POINTS | private static final int | MIN_CURVE_LENGTH | private final float[] | mRed | private final float[] | mGreen | private final float[] | mBlue | private int | mHashCode | private boolean | mHashCalculated |
Constructors Summary |
---|
public TonemapCurve(float[] red, float[] green, float[] blue)Create a new immutable TonemapCurve instance.
Values are stored as a contiguous array of {@code (Pin, Pout)} points.
All parameters may have independent length but should have at most
{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements and
at least 2 * {@value #POINT_SIZE} elements.
All sub-elements must be in the inclusive range of
[{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].
This constructor copies the array contents and does not retain ownership of the array.
// TODO: maxCurvePoints check?
checkNotNull(red, "red must not be null");
checkNotNull(green, "green must not be null");
checkNotNull(blue, "blue must not be null");
checkArgumentArrayLengthDivisibleBy(red, POINT_SIZE, "red");
checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
checkArgumentArrayLengthNoLessThan(red, MIN_CURVE_LENGTH, "red");
checkArgumentArrayLengthNoLessThan(green, MIN_CURVE_LENGTH, "green");
checkArgumentArrayLengthNoLessThan(blue, MIN_CURVE_LENGTH, "blue");
checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
mRed = Arrays.copyOf(red, red.length);
mGreen = Arrays.copyOf(green, green.length);
mBlue = Arrays.copyOf(blue, blue.length);
|
Methods Summary |
---|
private static void | checkArgumentArrayLengthDivisibleBy(float[] array, int divisible, java.lang.String arrayName)
if (array.length % divisible != 0) {
throw new IllegalArgumentException(arrayName + " size must be divisible by "
+ divisible);
}
| private static void | checkArgumentArrayLengthNoLessThan(float[] array, int minLength, java.lang.String arrayName)
if (array.length < minLength) {
throw new IllegalArgumentException(arrayName + " size must be at least "
+ minLength);
}
| private static int | checkArgumentColorChannel(int colorChannel)
switch (colorChannel) {
case CHANNEL_RED:
case CHANNEL_GREEN:
case CHANNEL_BLUE:
break;
default:
throw new IllegalArgumentException("colorChannel out of range");
}
return colorChannel;
| public void | copyColorCurve(int colorChannel, float[] destination, int offset)Copy the color curve for a single color channel from this tonemap curve into the destination.
Values are stored as packed {@code (Pin, Pout}) points, and there are a total of
{@link #getPointCount} points for that respective channel.
All returned coordinates are between the range of
[{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].
checkArgumentNonnegative(offset, "offset must not be negative");
checkNotNull(destination, "destination must not be null");
if (destination.length + offset < getPointCount(colorChannel) * POINT_SIZE) {
throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
}
float[] curve = getCurve(colorChannel);
System.arraycopy(curve, /*srcPos*/0, destination, offset, curve.length);
| private java.lang.String | curveToString(int colorChannel)
checkArgumentColorChannel(colorChannel);
StringBuilder sb = new StringBuilder("[");
float[] curve = getCurve(colorChannel);
int pointCount = curve.length / POINT_SIZE;
for (int i = 0, j = 0; i < pointCount; i++, j += 2) {
sb.append("(");
sb.append(curve[j]);
sb.append(", ");
sb.append(curve[j+1]);
sb.append("), ");
}
// trim extra ", " at the end. Guaranteed to work because pointCount >= 2
sb.setLength(sb.length() - 2);
sb.append("]");
return sb.toString();
| public boolean | equals(java.lang.Object obj)Check if this TonemapCurve is equal to another TonemapCurve.
Two matrices are equal if and only if all of their elements are
{@link Object#equals equal}.
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (obj instanceof TonemapCurve) {
final TonemapCurve other = (TonemapCurve) obj;
return Arrays.equals(mRed, other.mRed) &&
Arrays.equals(mGreen, other.mGreen) &&
Arrays.equals(mBlue, other.mBlue);
}
return false;
| private float[] | getCurve(int colorChannel)
switch (colorChannel) {
case CHANNEL_RED:
return mRed;
case CHANNEL_GREEN:
return mGreen;
case CHANNEL_BLUE:
return mBlue;
default:
throw new AssertionError("colorChannel out of range");
}
| public android.graphics.PointF | getPoint(int colorChannel, int index)Get the point for a color channel at a specified index.
The index must be at least 0 but no greater than {@link #getPointCount(int)} for
that {@code colorChannel}.
All returned coordinates in the point are between the range of
[{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].
checkArgumentColorChannel(colorChannel);
if (index < 0 || index >= getPointCount(colorChannel)) {
throw new IllegalArgumentException("index out of range");
}
final float[] curve = getCurve(colorChannel);
final float pIn = curve[index * POINT_SIZE + OFFSET_POINT_IN];
final float pOut = curve[index * POINT_SIZE + OFFSET_POINT_OUT];
return new PointF(pIn, pOut);
| public int | getPointCount(int colorChannel)Get the number of points stored in this tonemap curve for the specified color channel.
checkArgumentColorChannel(colorChannel);
return getCurve(colorChannel).length / POINT_SIZE;
| public int | hashCode(){@inheritDoc}
if (mHashCalculated) {
// Avoid re-calculating hash. Data is immutable so this is both legal and faster.
return mHashCode;
}
mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue);
mHashCalculated = true;
return mHashCode;
| public java.lang.String | toString()Return the TonemapCurve as a string representation.
{@code "TonemapCurve{R:[(%f, %f), (%f, %f) ... (%f, %f)], G:[(%f, %f), (%f, %f) ...
(%f, %f)], B:[(%f, %f), (%f, %f) ... (%f, %f)]}"},
where each {@code (%f, %f)} respectively represents one point of the corresponding
tonemap curve.
StringBuilder sb = new StringBuilder("TonemapCurve{");
sb.append("R:");
sb.append(curveToString(CHANNEL_RED));
sb.append(", G:");
sb.append(curveToString(CHANNEL_GREEN));
sb.append(", B:");
sb.append(curveToString(CHANNEL_BLUE));
sb.append("}");
return sb.toString();
|
|