Я получаю точный цвет пикселя и хотел бы связать этот точный цвет с константой, подобной 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];
}
}