Судя по вашим комментариям, вы, по сути, пытаетесь уменьшить полноцветную палитру растрового изображения только до 12, указанных вами. Очевидно, что для каждого пикселя в растровом изображении должно быть выбрано «лучшее совпадение» из этих 12.
Я до сих пор не понимаю, зачем вам нужны значения HSV, поскольку это просто другое представление компонентов RGB - на самом деле это не меняет проблему или ее решение.
Простой подход к поиску наилучшего соответствия для любого цвета RGB будет выглядеть примерно так:
Сначала создайте какой-то список, содержащий цвета, с которыми вы хотите сопоставить. Я использовал карту, так как вы упомянули, что вы (также) хотели знать имя цвета, а не только значение RGB.
Map<String, Integer> mColors = new HashMap<String, Integer>();
mColors.put("red", Color.rgb(255, 0, 0));
mColors.put("pink", Color.rgb(255, 192, 203));
mColors.put("voilet", Color.rgb(36, 10, 64));
mColors.put("blue", Color.rgb(0, 0, 255));
mColors.put("green", Color.rgb(0, 255, 0));
mColors.put("yellow", Color.rgb(255, 255, 0));
mColors.put("orange", Color.rgb(255, 104, 31));
mColors.put("white", Color.rgb(255, 255, 255));
mColors.put("black", Color.rgb(0, 0, 0));
mColors.put("gray", Color.rgb(128, 128, 128));
mColors.put("tea", Color.rgb(193, 186, 176));
mColors.put("cream", Color.rgb(255, 253, 208));
Тогда просто сделайте метод, который покажет вам лучшее совпадение. Вы можете вызвать это из вашего второго цикла for и передать ему текущий цвет пикселя. Я добавил несколько встроенных комментариев, чтобы объяснить различные шаги, но это действительно довольно тривиально.
private String getBestMatchingColorName(int pixelColor) {
// largest difference is 255 for every colour component
int currentDifference = 3 * 255;
// name of the best matching colour
String closestColorName = null;
// get int values for all three colour components of the pixel
int pixelColorR = Color.red(pixelColor);
int pixelColorG = Color.green(pixelColor);
int pixelColorB = Color.blue(pixelColor);
Iterator<String> colorNameIterator = mColors.keySet().iterator();
// continue iterating if the map contains a next colour and the difference is greater than zero.
// a difference of zero means we've found an exact match, so there's no point in iterating further.
while (colorNameIterator.hasNext() && currentDifference > 0) {
// this colour's name
String currentColorName = colorNameIterator.next();
// this colour's int value
int color = mColors.get(currentColorName);
// get int values for all three colour components of this colour
int colorR = Color.red(color);
int colorG = Color.green(color);
int colorB = Color.blue(color);
// calculate sum of absolute differences that indicates how good this match is
int difference = Math.abs(pixelColorR - colorR) + Math.abs(pixelColorG - colorG) + Math.abs(pixelColorB - colorB);
// a smaller difference means a better match, so keep track of it
if (currentDifference > difference) {
currentDifference = difference;
closestColorName = currentColorName;
}
}
return closestColorName;
}
Результаты быстрого теста с использованием некоторых предопределенных констант цвета:
Color.RED (-65536) -> red (-65536)
Color.GREEN (-16711936) -> green (-16711936)
Color.BLUE (-16776961) -> blue (-16776961)
Color.BLACK (-16777216) -> black (-16777216)
Color.WHITE (-1) -> white (-1)
Color.GRAY (-7829368) -> gray (-8355712)
Color.YELLOW (-256) -> yellow (-256)
Color.MAGENTA (-65281) -> pink (-16181)
Первое число в скобках - это фактическое значение int для константы Color, второе - значение int для наилучшего найденного соответствия с именем прямо перед ним.
Результат для Color.MAGENTA
также показывает, почему вы не должны просто сравнивать значение int цвета напрямую. Фактическое значение типа int -65281
, что довольно близко к значению Color.RED
(-65536). Тем не менее, наилучшим соответствием, основанным на различных компонентах, является «розовый», который имеет значение -16181. Очевидно, что это имеет смысл, зная, что цвет определяется как 4 байта:
Цвета представлены в виде упакованных целых, состоящих из 4 байтов: альфа, красный,
Зеленый, голубой. (...) Компоненты хранятся следующим образом (альфа << 24)
| (красный << 16) | (зеленый << 8) | синий. </p>
Источник: android.graphics.Color reference.
// Edit: со значениями HSV, похоже, тоже работает нормально. Я получил другой результат для «пурпурного», хотя и самый близкий - фиолетовый, вместо розового. Возможно, вы захотите перепроверить значения и некоторые контрольные точки. Например, я могу представить, что может быть лучше нормализовать часть «Н». Это зависит от вас ...
private String getBestMatchingHsvColor(int pixelColor) {
// largest difference is 360(H), 1(S), 1(V)
float currentDifference = 360 + 1 + 1;
// name of the best matching colour
String closestColorName = null;
// get HSV values for the pixel's colour
float[] pixelColorHsv = new float[3];
Color.colorToHSV(pixelColor, pixelColorHsv);
Iterator<String> colorNameIterator = mColors.keySet().iterator();
// continue iterating if the map contains a next colour and the difference is greater than zero.
// a difference of zero means we've found an exact match, so there's not point in iterating further.
while (colorNameIterator.hasNext() && currentDifference > 0) {
// this colour's name
String currentColorName = colorNameIterator.next();
// this colour's int value
int color = mColors.get(currentColorName);
// get HSV values for this colour
float[] colorHsv = new float[3];
Color.colorToHSV(color, colorHsv);
// calculate sum of absolute differences that indicates how good this match is
float difference = Math.abs(pixelColorHsv[0] - colorHsv[0]) + Math.abs(pixelColorHsv[1] - colorHsv[1]) + Math.abs(pixelColorHsv[2] - colorHsv[2]);
// a smaller difference means a better match, so store it
if (currentDifference > difference) {
currentDifference = difference;
closestColorName = currentColorName;
}
}
return closestColorName;
}