Search code examples
pythontkinterfade

Error: can't multiply sequence by non-int of type 'float'


I am trying to create a project where it is necessary to implement a fade image transition between two images. But i got error: can't multiply sequence by non-int of type 'float'

Here is my code:

import tkinter as tk
from PIL import ImageTk, Image

root = tk.Tk()

root.geometry('300x300')
root.resizable(width = True, height = True)

image1 = Image.open('name.jpg')
image2 = Image.open('name.png')

width = min(image1.width, image2.width)
height = min(image1.height, image2.height)

image1 = image1.resize((width, height),Image.ANTIALIAS)
image2 = image2.resize((width, height),Image.ANTIALIAS)

def ob_Fade(image1, image2, d):
    new_image = Image.new('RGB', (image1.width, image1.height), color='white')
    for x in range(image1.width):
        for y in range(image1.height):
            pixel_1 = image1.getpixel((x, y))
            pixel_2 = image2.getpixel((x, y))
            new_image.putpixel((x, y), (d * pixel_1 + (1 - d) * pixel_2))
    return new_image

def start():
    for i in range(0,100, 1):
        d = i/100
        image = ob_Fade(image1, image2, d)
        image = image.resize((250, 250),Image.ANTIALIAS)
        image = ImageTk.PhotoImage(image)
        image_label = tk.Label(root, image = image)
        image_label.image = image
        image_label.grid(row = 2, column = 1)

        root.update()
done = tk.Button(root, text="DO", padx=1, pady=0, command=start) 
done.grid(row = 0, column = 1) 
root.mainloop()

But I can't fix it with int(d), because if d is 0 then image 1 is copied, if d is 1 then image 2 is copied, this means that the transition will not happen at all.

Maybe someone could help?


Solution

  • This line returns a tuple:

    pixel_1 = image1.getpixel((x, y))
    

    e.g. pixel_1 is (2,3,4), that's why you cannot multiply a tuple by float and that's more or less what you are doing (example):

    7.89*(2,3,4)
    

    You have to iterate through the tuple and multiply in a loop/comprehension and then convert it back to a tuple (for a single pixel that would be):

    tuple([int(d*channel) for channel in pixel_1])
    

    In your case you need to iterate simultaneously over both pixels (or their channels to be exact) and calculate new pixel value based on both of them, taking d multiplied by channels from the 1st one and 1-d multiplied by the channels from the 2nd one:

    new_pixel_values = tuple([int(d*c1+(1-d)*c2) for c1, c2 in zip(pixel_1, pixel_2)])
    new_image.putpixel((x, y), new_pixel_values)