package Algorithms;
import Utils.Misc;
import java.util.Arrays;
public class PreprocessColor
{
static final float RED_WEIGHT = 0.299f;
static final float GREEN_WEIGHT = 0.587f;
static final float BLUE_WEIGHT = 0.114f;
public static boolean computeBrightnessTable(float[] table, int[] lineSegments, int nPoints)
{
if (nPoints <= 0)
return false;
long[] longPoints = new long[nPoints];
for (int i = 0; i < nPoints; i++)
longPoints[i] = ((long)lineSegments[2*i] << 32L) | ((long)lineSegments[2*i+1] & 0xFFFFffffL);
Arrays.sort(longPoints);
boolean invalid = false;
int highestX = (int)(longPoints[nPoints - 1] >> 32L);
if (highestX <= 0)
invalid = true;
if (table == null)
return !invalid;
int tableLen = table.length;
float size = (float)tableLen;
if (invalid) {
for (int i = 0; i < tableLen; i++)
table[i] = (float)i / size;
return false;
}
Arrays.fill(table, 0, tableLen, 0f);
float xScale = size / (float)highestX;
int x1 = (int)(longPoints[0] >> 32L);
int y1 = (int)(longPoints[0] & 0xFFFFffffL);
for (int i = 1; i < nPoints; i++) {
int x2 = (int)(longPoints[i] >> 32L);
int y2 = (int)(longPoints[i] & 0xFFFFffffL);
int start = (int)(x1 * xScale);
int end = (int)(x2 * xScale);
int len = end - start;
float yScale = 255f / (highestX * len);
for (int j = start, pos = 0; j < end; j++, pos++)
table[j] = (float)((len-pos) * y1 + pos * y2) * yScale;
x1 = x2;
y1 = y2;
}
return true;
}
public static void transformToMonoFloatArray(
float[] output,
int[] pixels,
int width,
int height,
float weightColor,
float weightBrightness,
int targetColor,
int voidColor,
float saturationFactor,
float[] brightnessTable
) {
if (weightColor <= 0f) {
computeImageBrightness(output, pixels, width, height, brightnessTable);
return;
}
float colorFactor = weightColor / (weightColor + Math.max(weightBrightness, 0f));
float brightnessFactor = 1f - colorFactor;
int area = width * height;
float targetHue = Misc.getHue(targetColor);
float voidHue = Misc.getHue(voidColor);
if (Float.isNaN(targetHue) || Float.isNaN(voidHue)) {
for (int i = 0; i < area; i++)
output[i] = 0f;
return;
}
float targetVoidDistance = Math.abs(targetHue - voidHue);
float narrowingFactor = 1f / Math.min(6f - targetVoidDistance, targetVoidDistance);
final float hueOppositeToTarget = (targetHue + 3f) % 6f;
float highestColorValue = 0f;
float nonSaturation = (1f - saturationFactor) * 255f;
for (int i = 0; i < area; i++) {
int rgb = pixels[i];
float r = (rgb >> 16) & 0xff;
float g = (rgb >> 8) & 0xff;
float b = rgb & 0xff;
float hue = hueOppositeToTarget;
float max = Math.max(Math.max(r, g), b);
float dMaxMin = max - Math.min(Math.min(r, g), b);
if (dMaxMin != 0f) {
if (max == (float)r) {
hue = (g - b) / dMaxMin;
}
else if (max == (float)g) {
hue = 2f + (b - r) / dMaxMin;
}
else {
hue = 4f + (r - g) / dMaxMin;
}
}
float dHue = Math.abs(hue - targetHue);
float diff = narrowingFactor * Math.min(6f - dHue, dHue);
float value = (saturationFactor * dMaxMin + nonSaturation) * Math.max(1f - diff, 0f);
output[i] = value;
highestColorValue = Math.max(highestColorValue, value);
}
float scaleFactor = highestColorValue > 0f ? 255f / highestColorValue : 255f;
float tableSizeWithScaling = (float)brightnessTable.length / 255f;
int highestIdx = brightnessTable.length - 1;
for (int i = 0; i < area; i++) {
float colorValue = Math.min(scaleFactor * output[i], 255f);
int rgb = pixels[i];
float r = RED_WEIGHT * ((rgb >> 16) & 0xff);
float g = GREEN_WEIGHT * ((rgb >> 8) & 0xff);
float b = BLUE_WEIGHT * (rgb & 0xff);
int idx = (int)(tableSizeWithScaling * (r+g+b));
float brightnessValue = brightnessTable[Math.min(idx, highestIdx)];
output[i] = colorFactor * colorValue + brightnessFactor * brightnessValue;
}
}
public static void computeImageBrightness(
float[] output,
int[] pixels,
int width,
int height,
float[] brightnessTable
) {
int area = width * height;
final float tableSizeWithScaling = (float)brightnessTable.length / 255f;
final int highestIdx = brightnessTable.length - 1;
for (int i = 0; i < area; i++) {
int rgb = pixels[i];
float r = RED_WEIGHT * ((rgb >> 16) & 0xff);
float g = GREEN_WEIGHT * ((rgb >> 8) & 0xff);
float b = BLUE_WEIGHT * (rgb & 0xff);
int idx = (int)(tableSizeWithScaling * (r+g+b));
output[i] = brightnessTable[Math.min(idx, highestIdx)];
}
}
}