Search code examples
pythonpython-3.4python-imaging-library

Python change gradient to start diagonally


I have a simple function that generates gradient. I would like to change the direction of the gradient to start diagonally top left.

im = Image.new('RGB', (300, 300))
ld = im.load()

# A map of rgb points in your distribution
# [distance, (r, g, b)]
# distance is percentage from left edge
heatmap = [

    [0.0, (0, 0, 0)],
    [1.00, (0.8, 0.0, 1.0)],
]


def gaussian(x, a, b, c, d=0):
    return a * math.exp(-(x - b) ** 2 / (2 * c ** 2)) + d


def pixel(x, width=100, map=[], spread=1):
    width = float(width)
    r = sum([gaussian(x, p[1][0], p[0] * width, width / (spread * len(map))) for p in map])
    g = sum([gaussian(x, p[1][1], p[0] * width, width / (spread * len(map))) for p in map])
    b = sum([gaussian(x, p[1][2], p[0] * width, width / (spread * len(map))) for p in map])
    return min(1.0, r), min(1.0, g), min(1.0, b)


for x in range(im.size[0]):
    r, g, b = pixel(x, width=300, map=heatmap)
    r, g, b = [int(256 * v) for v in (r, g, b)]
    for y in range(im.size[1]):
        ld[x, y] = r, g, b

I have found I can change the direction top to bottom and left to right but don't know how to change it diagonally.

for y in range(im.size[1]):
    ld[y, x] = r, g, b

Gives...

enter image description here

for y in range(im.size[1]):
    ld[x, y] = r, g, b

Gives...

enter image description here

Is this possible using the current functions and how?


Solution

  • Try something like this:

    heatmap = [
    
        [0.0, (0, 0, 0)],
        [1.00, (0.8, 0.0, 1.0)],
    ]
    
    # x y coordinates of starting point for gradient
    start_x = 0
    start_y = 0
    
    for x in range(im.size[0]):
        for y in range(im.size[1]):
            # taxicab distance for linear gradient 
            dist = math.fabs(start_x - x) + math.fabs(start_y - y)
            # for circular gradient
            # dist = math.sqrt(math.pow(start_x - x,2) + math.pow(start_y - y,2))
            start_rgb = heatmap[0][1]
            end_rgb = heatmap[1][1]
            dist = dist / (im.size[0] + im.size[1])
            # for circular gradient
            # dist = dist / (math.sqrt(math.pow(im.size[0],2) + math.pow(im.size[1],2)) 
            r, g, b = map(lambda x,y: x+y, map(lambda a: a*dist, start_rgb), map(lambda b: b*dist, end_rgb))
            r, g, b = [int(256 * v) for v in (r, g, b)]
            ld[x, y] = r, g, b
    

    I have assumed that start_x and start_y is located on one of the four corners of the image. Adjust start_x - x and start_y - y accordingly if it is not .