Создать уникальный цвет из строки - PullRequest
2 голосов
/ 06 июля 2011

Мне нужно нарисовать несколько произвольных строк в некоторых непрозрачных прямоугольных областях.Мне нужно, чтобы цвет фона этих областей был уникальным для данной строки.

Скажем, если я нарисую "Париж" и "Париж1", их цвет должен отличаться.Но если я нарисую «Париж» синим, то и другой «Париж» тоже должен быть нарисован синим.

Я еще раз подчеркиваю, что цвет должен быть непрозрачным.

Для этого я нашел простое решение:

rectangleBackColor = Color.FromArgb(myString.GetHashCode())

Проблема в непрозрачности.Мне нужно «исключить» компонент «A» (альфа).

Теперь такой код может работать

  rectangleBackColor = Color.FromArgb(myString.GetHashCode())
  ' set the alpha value = 255 for an opaque color '
  rectangleBackColor = Color.FromArgb(255, rectangleBackColor) 

, но он может потерять уникальность строкового цвета.

Скажем, у меня есть два разных хеш-кода (в гекса) x AB 11 22 33 и x FF 11 22 33.
Установка AB в FF Я делаю для двух разных строк один и тот же цвет фона (x FF 11 22 33).Это не хорошо.

Ответы [ 4 ]

2 голосов
/ 06 июля 2011

Вы не можете генерировать уникальные цвета для строк:

Пространство RGB имеет 24 бита или 2 ^ 24-1 уникальных значений (всего 16777215 цветов).

Следующий код напечатает 16777220 уникальных строк (на 5 больше, чем количество цветов):

for(int i=0; i<16777220 ; ++i) Console.WriteLine(i.ToString());

Итак, если вы возьмете все строки, сгенерированные вышеприведенной программой, и дадите цвет, у вас должно быть как минимум 5 строк с повторяющимися цветами.

Кстати, GetHashCode не возвращает уникальные значения, только равномерно распределенные, повторите приведенное выше доказательство с 32 битами (вам нужно сделать i в цикле for uint и изменить число на более чем 4294967295, но это только изменения), и вы обнаружите, что не можете получить уникальное значение для каждой строки в 32-битном значении (или в любом другом значении фиксированного размера).

Ваш метод довольно хорош, и повторные цвета, вероятно, будут редкими.

2 голосов
/ 06 июля 2011

Учитывая, что вы не можете сгенерировать действительно уникальное целое число для представления строки из-за разницы в размере пробелов, которые они могут представлять, вы можете попробовать:

uint noA = (unit)myString.GetHashCode() / 255; 
uint opaque = noA + 0xFF000000; 
rectangleBackColor = Color.FromArgb(opaque);

Это должно сгенерировать (довольно) уникальное значение для каждой строки на основе хеш-кода с альфа-компонентом, установленным на 255. Ясно, что это может генерировать только 2 ^ 24 различных значений, и, следовательно, не является действительно уникальным.

Изменить: Следует отметить, что это имеет ту же проблему, что и ваша версия, но игнорирует младшие 8 бит вместо старших.

1 голос
/ 06 июля 2011

Хэш не уникален в первую очередь. Если вы не уверены, просто подумайте, сколько строк больше, чем хэш-код. Начнем с того, что хеш-код сами по себе являются строками! Это означает, что если бы вы приписывали разные хеш-коды каждой строке, вы бы исчерпали хеш-код после прохождения всего хеш-кода.

Две строки, имеющие одинаковый хэш-код, называются коллизиями. Для хорошего хэш-кода вы можете считать, что вероятность того, что две невинные строки будут в 1 / # {размере вашего хэш-пространства}.

Еще одним приятным свойством является то, что вы ожидаете, что любое усечение вашего хеш-кода будет вести себя так же. Усечение вашего хеш-кода - это правильная практика.

Вы получите для двух данных имен вероятность столкновения около 1 / 16M. Однако, если у вас есть N-строки, вы можете столкнуться с так называемой проблемой дня рождения . Вероятность наблюдения как минимум 1 столкновения намного выше. Где-то рядом, чем N ^ 2 / 16M.

0 голосов
/ 06 июля 2011

Две идеи:

1) Если все ваши N строк известны до того, как вы начнете раскрашивать, вычислите Perfect Hash (реализации в C и C # здесь). Затем вы можете умножить каждое хеш-значение на 256 ^ 3 / N, чтобы распределить результаты по цветовому пространству.

2) Если они не известны, вы можете разрешить столкновения вручную. Примерно такой псевдокод:

tries = 5; //arbitrary number       
colorcode = myString.GetHashCode()&0xFFFFFF;
while ( Dictionary.containsKey(colorcode ) && 
        Dictionary.getValue(colorcode )!= myString &&
        tries-->0) {
    colorcode = ((colorcode+3) * 92821) &0xFFFFFF;  //rehash
}
if (tries) {
    Dictionary.insert(colorcode , myString);
} 
rectangleBackColor = Color.FromArgb(0xFF000000|colorcode ); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...