Я получаю точный цвет пикселя и хотел бы связать этот точный цвет с константой, подобной Color.blue. Есть ли простой способ "округлить" до ближайшей цветовой константы? Кроме того, есть ли способ определить ваши собственные цветовые константы?
Каков наилучший способ "округлить" объект "Цвет" до ближайшей цветовой константы?
Ответ 1
Основной подход заключается в том, чтобы найти ближайший стандартный цвет для вашего образца, просто сравнивая образец с каждым из них. Проблема, конечно, заключается в определении "ближайшего". Наиболее очевидным было бы использование евклидова расстояния в пространстве RGB. Проблема в том, что это расстояние не очень хорошо согласуется с нашим восприятием "самого близкого цвета". Обсуждение этой проблемы, наряду с хорошей (легко вычисляемой) метрикой (включая псевдокод!), Можно найти в этой статье.
РЕДАКТИРОВАТЬ: просто в случае, если ссылка на этот документ не работает (или если вы ленивы и хотите использовать код, не понимая, что он делает), здесь моя Java-версия "функции цветового расстояния", которую статья предлагает как "низкий "приближение стоимости" к их рекомендуемой функции расстояния (взвешенное евклидово расстояние в пространстве RGB):
double colorDistance(Color c1, Color c2)
{
int red1 = c1.getRed();
int red2 = c2.getRed();
int rmean = (red1 + red2) >> 1;
int r = red1 - red2;
int g = c1.getGreen() - c2.getGreen();
int b = c1.getBlue() - c2.getBlue();
return Math.sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
Обратите внимание, что если вы просто собираетесь ранжировать цветовые расстояния, вы можете обойтись без вызова Math.sqrt(), что сэкономит некоторые вычислительные затраты.
Ответ 2
Вероятно, лучшим способом было бы getRed каждую константу и сравнить их соответствующие каналы RGB (getRed, getGreen, getBlue). Следите за тем, который ближе всего.
Color color = new Color(...);
Color[] constantColors = new Color[] { Color.black, Color.blue, Color.cyan, Color.darkGray, Color.gray, Color.green, Color.lightGray, Color.magenta, Color.orange, Color.pink, Color.red, Color.white, Color.yellow };
Color nearestColor = null;
Integer nearestDistance = new Integer(Integer.MAX_VALUE);
for (Color constantColor : constantColors) {
if (nearestDistance > Math.sqrt(
Math.pow(color.getRed() - constantColor.getRed(), 2)
- Math.pow(color.getGreen() - constantColor.getGreen(), 2)
- Math.pow(color.getBlue() - constantColor.getBlue(), 2)
)
) {
nearestColor = color;
}
}
Нет, вы не можете добавить цветовые константы в класс, но вы можете создать собственный класс для хранения констант.
class MyColors {
public static final Color heliotrope = new Color(...);
}
Изменить: добавлен алгоритм разницы, благодаря ссылке @Ted.
Ответ 3
Вы можете использовать встроенное преобразование цвета Java с помощью IndexColorModel, содержащего палитру возможных цветов. Внутренне класс использует эвклидовое расстояние над цветовыми компонентами для определения ближайшего цвета.
import java.awt.Color;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
public class ColorConverter {
private final Color[] colors;
private final IndexColorModel colorModel;
public ColorConverter(Color[] colors) {
this.colors = colors;
this.colorModel = createColorModel(colors);
}
private static IndexColorModel createColorModel(Color[] colors) {
final int[] cmap = new int[colors.length];
for (int i = 0; i<colors.length; i++) {
cmap[i] = colors[i].getRGB();
}
final int bits = (int) Math.ceil(Math.log(cmap.length)/Math.log(2));
return new IndexColorModel(bits, cmap.length, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
}
public Color nearestColor(Color color) {
final byte index = ((byte[])colorModel.getDataElements(color.getRGB(), null))[0];
return colors[index];
}
}