Q&A
前提
pythonのtkinterでクリックにより画像を回転させ、再度クリックすることで回転が止まるアニメーションを作成しています。
afterメソッドで無限に画像を回転させる処理を行ったうえで、後から回転をストップさせるイベントを呼び出し、アニメーションの操作を実現しています。
画像を角速度5[deg/s]で回転させようとしているにも関わらず、想定より回転速度が遅いことに困っています。
おそらく、処理が重いことが大きな要因の一つだと思われます。
実現したいこと
画像を角速度5[deg/s]で回転させたいです。
しかし、現在備わっている
・左クリックで左回転スタート
・右クリックで右回転スタート
・左右いづれかのクリックで回転をストップ
という機能は必要です。
このような機能を保ちつつ、処理を軽くして角速度を命令通りに実行できるコードにするには、どのような改良をすると良いでしょうか?
該当のソースコード
python
1import tkinter as tk 2from PIL import Image, ImageTk 3import datetime 4 5 6#新規ウィンドウを作成 7root = tk.Tk() 8root.attributes("-fullscreen", True) 9 10 11#画面サイズの指定 12WIDTH = root.winfo_screenwidth() 13HEIGHT = root.winfo_screenheight() 14 15 16#ウィンドウ上にフレームを作成 17frame = tk.Frame(root) 18frame.place(x = -5, y = -5, width = WIDTH + 10, height = HEIGHT + 10) 19 20 21#フレーム上に、キャンバスを作成 22canvas = tk.Canvas(frame, width = WIDTH, height = HEIGHT, bg = "black") 23canvas.place(x = 0, y = 0, width = WIDTH + 10, height = HEIGHT + 10) 24 25 26#画像のプリセット角を"cs"として定義 27cs = 0 28 29 30#キャンバスにSVV画像を貼り付け 31img = Image.open("D:\EXPERIMENT\programming\Python\SVV\svv_bar.png") 32img = img.rotate(cs) 33tkimg = ImageTk.PhotoImage(img, width = WIDTH, height = HEIGHT) 34canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg, anchor="center", tags="img") 35 36 37#キャンバスに、透明な画像を貼り付け 38img_snow = Image.open("D:\EXPERIMENT\programming\Python\SVV\svv_snow.png") 39tkimg_snow = ImageTk.PhotoImage(img_snow, width = WIDTH, height = HEIGHT) 40canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor="center", tags="img_snow") 41 42 43#"c"の初期値を定義 44c = 0 45 46 47#角速度の指定 48interval = datetime.timedelta(milliseconds = 20) 49 50 51#左回転時の基準時刻を取得し、press_Lに渡す 52def press_L(event): 53 global next_time_L 54 next_time_L = datetime.datetime.now() 55 rotate_L(event) 56 57 58#右回転時の基準時刻を取得し、press_Rに渡す 59def press_R(event): 60 global next_time_R 61 next_time_R = datetime.datetime.now() 62 rotate_R(event) 63 64 65def rotate_L(event): 66 global interval 67 global next_time_L 68 global img 69 global tkimg 70 global c 71 c = c + 1 72 R = c / 10 73 canvas.delete("all") 74 IMG = img.rotate(R, resample = Image.BICUBIC) 75 tkimg = ImageTk.PhotoImage(IMG) 76 canvas.create_image(WIDTH/2, HEIGHT/2, image = tkimg, anchor = "center", tags = "img") 77 canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor = "center", tags="img_snow") 78 next_time_L += interval 79 now = datetime.datetime.now() 80 delay_ms = int((next_time_L - now).total_seconds() * 1000) 81 id = root.after(delay_ms, rotate_L, None) 82 def stop_L(event): 83 root.after_cancel(id) 84 canvas.tag_bind("img_snow", "<ButtonPress-1>", press_L) 85 canvas.bind("<ButtonRelease-1>", stop_L) 86 87 88def rotate_R(event): 89 global interval 90 global next_time_R 91 global img 92 global tkimg 93 global c 94 c = c - 1 95 R = c / 10 96 canvas.delete("all") 97 IMG = img.rotate(R, resample = Image.BICUBIC) 98 tkimg = ImageTk.PhotoImage(IMG) 99 canvas.create_image(WIDTH/2, HEIGHT/2, image = tkimg, anchor = "center", tags = "img") 100 canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor = "center", tags="img_snow") 101 next_time_R += interval 102 now = datetime.datetime.now() 103 delay_ms = int((next_time_R - now).total_seconds() * 1000) 104 id = root.after(delay_ms, rotate_R, None) 105 def stop_R(event): 106 root.after_cancel(id) 107 canvas.tag_bind("img_snow", "<ButtonPress-3>", press_R) 108 canvas.bind("<ButtonRelease-3>", stop_R) 109 110 111def finish(event): 112 #Enterキーを押すことで全画面表示を終了し、回転角度を取得する 113 root.destroy() 114 print(-c / 10) 115 116 117#左クリックで呼び出すイベント 118canvas.tag_bind("img_snow", "<ButtonPress-1>", press_L) 119 120 121#右クリックで呼び出すイベント 122canvas.tag_bind("img_snow", "<ButtonPress-3>", press_R) 123 124 125#Enterキーで呼び出すイベント 126root.bind("<Return>", finish) 127 128 129#メインループ 130root.mainloop() 131 132 133#end. 134
上記の処理に使用した画像を作成するコード
python
1from PIL import Image, ImageDraw 2 3#背景色が黒色のキャンパスを作成。 4im = Image.new('RGB', (500, 500), (0, 0, 0)) 5draw = ImageDraw.Draw(im) 6 7 8#中央に線を描画 9draw.line((50, 250, 450, 250), fill=(255, 255, 255), width=10) 10 11 12#同じサイズの画像を作成 13im_clear = Image.new("RGBA", im.size, (0, 0, 0, 0)) 14width = im.size[0] 15height = im.size[1] 16 17 18#色ごとに処理 19for x in range(width): 20 for y in range(height): 21 pixel = im.getpixel( (x, y) ) 22 23 # 黒なら処理しない 24 if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0: 25 continue 26 27 # 黒以外なら、用意した画像にピクセルを書き込み 28 im_clear.putpixel( (x, y), pixel ) 29 30 31#SVVで表示させるバーをpng形式で保存 32im_clear.save("D:\EXPERIMENT\programming\Python\SVV\svv_bar.png", quality=100) 33 34 35 36#---透明なpng画像の作成--- 37 38#画像サイズの指定 39WIDTH = 1600 40HEIGHT = 1000 41 42 43#新しい画像を作成 44im_snow = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) 45 46 47#新しい画像をもう一つ作成 48im_snow2 = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) 49 50 51#色ごとに処理 52for x in range(width): 53 for y in range(height): 54 pixel = im_snow2.getpixel( (x, y) ) 55 56 # 黒なら処理しない 57 if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0: 58 continue 59 60 # 黒以外なら、用意した画像にピクセルを書き込み 61 im_snow.putpixel( (x, y), pixel ) 62 63 64#透明な画像をpng形式で保存 65im_snow.save("D:\EXPERIMENT\programming\Python\SVV\svv_snow.png", quality=100) 66
試したこと
afterメソッドの指定時間を増やして、それに伴い "c + 0.005" の部分の数値を大きくするように変更しましたが、アニメーションがカクカク動いているように見えてしまうレベルまで処理の時間間隔を空けても、画像が360°回転するのに72秒以上の時間がかかってしまいました。
そのため、コードの改良が必要だと感じています。
呼び出すイベント関数が多いことが原因かと考え、関数の数を減らそうと試みましたが、現時点の数までしか減らせませんでした。
もし、さらに処理が軽くなるコードを思いつく方がいらっしゃいましたら、お力を貸して頂きたいです。
補足情報(FW/ツールのバージョンなど)
AnacondaでPythonを使用しています。
・Anacondaのバージョン:conda 4.12.0
・Pythonのバージョン:Python 3.9.12
・Windowsのバージョン:version 21H2
デバイスの仕様
・プロセッサ:11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz 2.80 GHz
・実装RAM:16.0 GB
回答1件
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2022/09/02 07:26
2022/09/02 08:25 編集
2022/09/05 06:04
2022/09/05 12:27 編集
2022/09/06 07:58 編集
2022/09/06 08:02
2022/09/06 10:29 編集
2022/09/06 12:35 編集
2022/09/06 13:23 編集
2022/09/06 13:49
2022/09/06 14:05
2022/09/06 14:49 編集
2022/09/07 02:36 編集
2022/09/07 02:56
2022/09/07 03:31 編集
2022/09/07 03:30
2022/09/07 06:13
2022/09/07 06:17 編集
2022/09/07 06:49
2022/09/07 11:38
2022/09/08 05:36
2022/09/08 06:13
2022/09/08 07:35