这是一种在不使用 PIL 模块的情况下使用 tkinter 旋转图像的方法。
所以在我给出答案之前,这里有一些解释。
首先,画布坐标有一个负 y 轴,因此在考虑数学时需要小心这一点。我选择转换为“标准”系统。然后后来我转换回来。不管你做什么,都要小心,因为它很容易混淆。
这是一个基本大纲:
- 制作一个新的空白图像,它可能需要更大以容纳旋转的图像。
- 逐像素遍历,得到原始图像中的颜色。
- 将颜色放入新图像的像素中,但在新图像的新区域中
这是关于如何旋转图像的更深入的概述(我选择将轴更改为更“标准”的数学坐标,其中正 y 值向上,而不是像很多计算机一样向下。)
- 将 y 轴更改为“标准”数学坐标 - 这意味着图像将位于笛卡尔坐标系的“象限 4”中(x 为正,y 为负)
- 移动图片位置,使原点位于图片中间 - 现在图片位于所有 4 个象限中,图片中间为 (0,0)
- 围绕原点 (0,0) 应用标准旋转公式以获得新的像素坐标
- 现在将图像放回“象限 4”(图像可能更大,旋转后可能需要移动更多。
- 将坐标系改回y向下是正坐标系。
事实证明(您可以自己拿一张 3x5 的记事卡并在一张纸上旋转来验证这一点),使用对角线测量新的宽度和高度总是足够大以容纳新的旋转图像。
所以这是一个旋转图像的函数:
from math import sin, cos, sqrt, pi
from tkinter import *
#returns a rotated PhotoImage
def rotatedPhotoImage(img, angle):
angleInRads = angle * pi / 180
diagonal = sqrt(img.width()**2 + img.height()**2)
xmidpoint = img.width()/2
ymidpoint = img.height()/2
newPhotoImage = PhotoImage(width=int(diagonal), height=int(diagonal))
for x in range(img.width()):
for y in range(img.height()):
# convert to ordinary mathematical coordinates
xnew = float(x)
ynew = float(-y)
# shift to origin
xnew = xnew - xmidpoint
ynew = ynew + ymidpoint
# new rotated variables, rotated around origin (0,0) using simoultaneous assigment
xnew, ynew = xnew*cos(angleInRads) - ynew*sin(angleInRads), xnew * sin(angleInRads) + ynew*cos(angleInRads)
# shift back to quadrant iv (x,-y), but centered in bigger box
xnew = xnew + diagonal/2
ynew = ynew - diagonal/2
# convert to -y coordinates
xnew = xnew
ynew = -ynew
# get pixel data from the pixel being rotated in hex format
rgb = '#%02x%02x%02x' % img.get(x, y)
# put that pixel data into the new image
newPhotoImage.put(rgb, (int(xnew), int(ynew)))
# this helps fill in empty pixels due to rounding issues
newPhotoImage.put(rgb, (int(xnew+1), int(ynew)))
return newPhotoImage
这是用于旋转的函数,例如 34 度。
root = Tk()
mycanvas = Canvas(root, width=300, height=300)
mycanvas.pack()
myPhotoImage=PhotoImage(file="car.png")
myPhotoImage=rotatedPhotoImage(myPhotoImage,34)
canvasImage=mycanvas.create_image(150,150,image=myPhotoImage)
这是旋转后的汽车截图:
这是使用该函数旋转汽车图像的示例。请注意,转换图像需要一些时间,具体取决于大小,但在此之后可以使用图像数组。对于这张汽车图片:
为我转换图像需要 3 秒。
from math import sin, cos, sqrt, pi
from tkinter import *
from time import sleep
def getImageIndex(angle):
# resets 360 to 0
angle = angle % 360
# using 16 images: 360/16 is 22.5 degrees, 11.25 is 1/2 of 22.5
index = (angle-11.25)/22.5 + 1
index = int(index)
index = index % 16
return index
root = Tk()
originalImage = PhotoImage(file="car.png")
carImages = []
for i in range(16): # using 16 images
angle = i*22.5 # 360degrees/16 images = 22.5 degrees
carImages.append(rotatedPhotoImage(originalImage, angle))
mycanvas = Canvas(root, width=300, height=300)
mycanvas.pack()
canvasimage = mycanvas.create_image(150, 150, image=carImages[0], anchor=CENTER)
for i in range(1440): #spins 4 times around
mycanvas.delete(canvasimage)
canvasimage = mycanvas.create_image(150, 150, image=carImages[getImageIndex(i)], anchor=CENTER)
root.update()
sleep(.001)
root.mainloop()
注意汽车背景不透明。
这似乎仅限于使用基本的 tkinter 模块,但是如果您可以通过替换像白色这样的颜色来代替使用 alpha (r,g,b,a),这里稍微有点该功能的更高级版本,它跳过写入您选择的颜色的像素及其使用示例。
这是汽车,我已将其背景颜色更改为白色。
这是一个程序,清除白色像素,制作一组图像并在橙色背景上旋转它们。该程序中使用的函数包含一个可选的背景颜色去除器。
from math import sin, cos, sqrt, pi
from tkinter import *
from time import sleep
# returns a rotated PhotoImage
def rotatedPhotoImage(img, angle, colorToMakeTransparentInHexFormat=""):
angleInRads = angle * pi / 180
diagonal = sqrt(img.width()**2 + img.height()**2)
xmidpoint = img.width()/2
ymidpoint = img.height()/2
newPhotoImage = PhotoImage(width=int(diagonal), height=int(diagonal))
for x in range(img.width()):
for y in range(img.height()):
# convert to ordinary mathematical coordinates
xnew = float(x)
ynew = float(-y)
# shift to origin
xnew = xnew - xmidpoint
ynew = ynew + ymidpoint
# new rotated variables, rotated around origin (0,0) using simoultaneous assigment
xnew, ynew = xnew*cos(angleInRads) - ynew*sin(angleInRads), xnew * sin(angleInRads) + ynew*cos(angleInRads)
# shift back to quadrant iv (x,-y), but centered in bigger box
xnew = xnew + diagonal/2
ynew = ynew - diagonal/2
# convert to -y coordinates
xnew = xnew
ynew = -ynew
# get pixel data from the pixel being rotated in hex format
rgb = '#%02x%02x%02x' % img.get(x, y)
if rgb != colorToMakeTransparentInHexFormat:
# put that pixel data into the new image
newPhotoImage.put(rgb, (int(xnew), int(ynew)))
# this helps fill in empty pixels due to rounding issues
newPhotoImage.put(rgb, (int(xnew+1), int(ynew)))
return newPhotoImage
def getImageIndex(angle):
# resets 360 to 0
angle = angle % 360
# using 16 images: 360/16 is 22.5 degrees, 11.25 is 1/2 of 22.5
index = (angle-11.25)/22.5 + 1
index = int(index)
index = index % 16
return index
root = Tk()
originalImage = PhotoImage(file="carwhitebg.png")
carImages = []
for i in range(16): # using 16 images
angle = i*22.5 # 360degrees/16 images = 22.5 degrees
carImages.append(rotatedPhotoImage(originalImage, angle,"#ffffff"))
mycanvas = Canvas(root, width=300, height=300,bg="orange")
mycanvas.pack()
canvasimage = mycanvas.create_image(150, 150, image=carImages[0], anchor=CENTER)
for i in range(943): #some arbitrary number of degrees
mycanvas.delete(canvasimage)
canvasimage = mycanvas.create_image(150, 150, image=carImages[getImageIndex(i)], anchor=CENTER)
root.update()
sleep(.001)
root.mainloop()
下面是橙色背景上那辆车的示例:
希望我在尝试回答这个问题时增加了一些价值。 H5>
- 我没有使用 PIL
- 我允许旋转到任意角度
- 我展示了一个旋转汽车的演示
- 我还展示了如何选择颜色以使图像透明