Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Get random color, given a seed number as fast as possible

I need to find a random color, given a specific seed number - fast. given the same ID twice, should return the same color.

I did this:

def id_to_random_color(number):
    random_bytes = hashlib.sha1(bytes(number)).digest()
    return [int(random_bytes[-1]) / 255, int(random_bytes[-2]) / 255, int(random_bytes[-3]) / 255, 1.0]

The problem is that calculating the sha1 of numbers many times is very slow in total. (I'm using this function about 100k times)

Edit: The reason I use a hash function is that I want to have colors that are different for numbers that are close

e.g id_to_random_color(7) should be very different from id_to_random_color(9)

like image 340
user972014 Avatar asked Oct 10 '18 14:10

user972014


People also ask

How do you randomize colors in Python?

In the hexadecimal format, the #symbol is followed by six hexadecimal numbers. RGB colors are hexadecimal colors. To acquire a random color, the random() method is used. Random() is a commonly used Python module that can produce random integers or colors.

What does random seed () do?

Python Random seed() Method The seed() method is used to initialize the random number generator. The random number generator needs a number to start with (a seed value), to be able to generate a random number. By default the random number generator uses the current system time.

How do you generate a random seed in Python?

To generate random number in Python, randint() function is used. This function is defined in random module.

How do you pick a random seed?

Many researchers worry about how to choose a random number seed. Some people use an easy-to-remember sequence such as their phone number or the first few digits of pi. Others use long prime numbers such as 937162211.


1 Answers

Using simple random number generators with kind of static variables could improve performance:

import random
prev, r, g, b = None, 0, 0, 0
def id_to_random_color(number):
    global prev, r, g, b
    if number != prev:
        r = random.random()
        g = random.random()
        b = random.random()
        prev = number
    return r, g, b, 1.0

Update:
As AndrewMcDowell stated in his comment, the function could return different values if the input is repeated in not sequential occasions.
Here is a possible workaround:

import random
memory = {}
def id_to_random_color(number, memory):
    if not number in memory:
        r = random.random()
        g = random.random()
        b = random.random()
        memory[number] = (r, g, b, 1.0)
    return memory[number]

Further update:
The same function skeleton could be used even to calculate hash:

memory = {}
def id_to_random_color(number):
    if not number in memory:
        numByte = str.encode(number)
        hashObj = hashlib.sha1(numByte).digest()
        r, g, b = hashObj[-1] / 255.0, hashObj[-2] / 255.0, hashObj[-3] / 255.0
        memory[number]= (r, g, b, 1.0)
        return r, g, b, 1.0
    else:
        return memory[number]

Despite it is a bit more verbose syntax, the else statement improves a bit performances, avoiding subsequent memory write and read (as Jake stated in his answer).

like image 132
rudicangiotti Avatar answered Sep 28 '22 20:09

rudicangiotti