質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

1回答

1435閲覧

画像を複数表示しそれぞれ拡大縮小・移動ができるようにしたい

MSA

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

0クリップ

投稿2022/01/17 10:45

複数の画像を表示し、それぞれ拡大縮小・移動ができるようにしたいです。

現在、一つの画像に対して拡大縮小移動はできるのですが、画像を選択しなおすとそれまで表示されていた画像が消え新たに選択された画像に置き換わります。これを複数の画像を随時選択して表示し、さらにそれぞれ拡大縮小・移動ができるようにしたいです。

python初心者で恥ずかしながらこのコードも下記のサイトからほぼコピペさせてもらいました。そこから必要でない箇所を省いた次第です。色々調べやってみたのですがうまくいきません。どなたか教えてください。

参考にしたサイト

python

1import tkinter as tk # ウィンドウ作成用 2from tkinter import filedialog # ファイルを開くダイアログ用 3from PIL import Image, ImageTk # 画像データ用 4import numpy as np # アフィン変換行列演算用 5import os # ディレクトリ操作用 6 7class Application(tk.Frame): 8 def __init__(self, master=None): 9 super().__init__(master) 10 self.pack() 11 12 self.pil_image = None # 表示する画像データ 13 self.my_title = "Image Viewer" # タイトル 14 self.back_color = "#008B8B" # 背景色 15 16 # ウィンドウの設定 17 self.master.title(self.my_title) # タイトル 18 self.master.geometry("500x400") # サイズ 19 20 self.create_menu() # メニューの作成 21 self.create_widget() # ウィジェットの作成 22 23 def menu_open_clicked(self, event=None): 24 # ファイル→開く 25 filename = tk.filedialog.askopenfilename( 26 filetypes = [("Image file", ".bmp .png .jpg .tif"), ("Bitmap", ".bmp"), ("PNG", ".png"), ("JPEG", ".jpg"), ("Tiff", ".tif") ], # ファイルフィルタ 27 initialdir = os.getcwd() # カレントディレクトリ 28 ) 29 30 # 画像ファイルを設定する 31 self.set_image(filename) 32 33 def menu_quit_clicked(self): 34 # ウィンドウを閉じる 35 self.master.destroy() 36 37 # create_menuメソッドを定義 38 def create_menu(self): 39 self.menu_bar = tk.Menu(self) # Menuクラスからmenu_barインスタンスを生成 40 41 self.file_menu = tk.Menu(self.menu_bar, tearoff = tk.OFF) 42 self.menu_bar.add_cascade(label="File", menu=self.file_menu) 43 44 self.file_menu.add_command(label="Open", command = self.menu_open_clicked, accelerator="Ctrl+O") 45 self.file_menu.add_separator() # セパレーターを追加 46 self.file_menu.add_command(label="Exit", command = self.menu_quit_clicked) 47 48 self.menu_bar.bind_all("<Control-o>", self.menu_open_clicked) # ファイルを開くのショートカット(Ctrol-Oボタン) 49 50 self.master.config(menu=self.menu_bar) # メニューバーの配置 51 52 def create_widget(self): 53 '''ウィジェットの作成''' 54 55 # Canvas 56 self.canvas = tk.Canvas(self.master, background= self.back_color) 57 self.canvas.pack(expand=True, fill=tk.BOTH) # この両方でDock.Fillと同じ 58 59 # マウスイベント 60 self.master.bind("<Motion>", self.mouse_move) # MouseMove 61 self.master.bind("<B1-Motion>", self.mouse_move_left) # MouseMove(左ボタンを押しながら移動) 62 self.master.bind("<Button-1>", self.mouse_down_left) # MouseDown(左ボタン) 63 self.master.bind("<Double-Button-1>", self.mouse_double_click_left) # MouseDoubleClick(左ボタン) 64 self.master.bind("<MouseWheel>", self.mouse_wheel) # MouseWheel 65 66 def set_image(self, filename): 67 ''' 画像ファイルを開く ''' 68 if not filename: 69 return 70 # PIL.Imageで開く 71 self.pil_image = Image.open(filename) 72 # 画像全体に表示するようにアフィン変換行列を設定 73 self.zoom_fit(self.pil_image.width, self.pil_image.height) 74 # 画像の表示 75 self.draw_image(self.pil_image) 76 # カレントディレクトリの設定 77 os.chdir(os.path.dirname(filename)) 78 79 # ------------------------------------------------------------------------------- 80 # マウスイベント 81 # ------------------------------------------------------------------------------- 82 83 def mouse_move(self, event): 84 ''' マウスの移動時 ''' 85 86 if self.pil_image == None: 87 return 88 89 # 画像座標 90 mouse_posi = np.array([event.x, event.y, 1]) # マウス座標(numpyのベクトル) 91 mat_inv = np.linalg.inv(self.mat_affine) # 逆行列(画像→Cancasの変換からCanvas→画像の変換へ) 92 image_posi = np.dot(mat_inv, mouse_posi) # 座標のアフィン変換 93 x = int(np.floor(image_posi[0])) 94 y = int(np.floor(image_posi[1])) 95 if x >= 0 and x < self.pil_image.width and y >= 0 and y < self.pil_image.height: 96 # 輝度値の取得 97 value = self.pil_image.getpixel((x, y)) 98 99 100 def mouse_move_left(self, event): 101 ''' マウスの左ボタンをドラッグ ''' 102 if self.pil_image == None: 103 return 104 self.translate(event.x - self.__old_event.x, event.y - self.__old_event.y) 105 self.redraw_image() # 再描画 106 self.__old_event = event 107 108 def mouse_down_left(self, event): 109 ''' マウスの左ボタンを押した ''' 110 self.__old_event = event 111 112 def mouse_double_click_left(self, event): 113 ''' マウスの左ボタンをダブルクリック ''' 114 if self.pil_image == None: 115 return 116 self.zoom_fit(self.pil_image.width, self.pil_image.height) 117 self.redraw_image() # 再描画 118 119 def mouse_wheel(self, event): 120 ''' マウスホイールを回した ''' 121 if self.pil_image == None: 122 return 123 124 if (event.delta < 0): 125 # 上に回転の場合、縮小 126 self.scale_at(0.8, event.x, event.y) 127 else: 128 # 下に回転の場合、拡大 129 self.scale_at(1.25, event.x, event.y) 130 131 self.redraw_image() # 再描画 132 133 # ------------------------------------------------------------------------------- 134 # 画像表示用アフィン変換 135 # ------------------------------------------------------------------------------- 136 137 def reset_transform(self): 138 '''アフィン変換を初期化(スケール1、移動なし)に戻す''' 139 self.mat_affine = np.eye(3) # 3x3の単位行列 140 141 def translate(self, offset_x, offset_y): 142 ''' 平行移動 ''' 143 mat = np.eye(3) # 3x3の単位行列 144 mat[0, 2] = float(offset_x) 145 mat[1, 2] = float(offset_y) 146 147 self.mat_affine = np.dot(mat, self.mat_affine) 148 149 def scale(self, scale:float): 150 ''' 拡大縮小 ''' 151 mat = np.eye(3) # 単位行列 152 mat[0, 0] = scale 153 mat[1, 1] = scale 154 155 self.mat_affine = np.dot(mat, self.mat_affine) 156 157 def scale_at(self, scale:float, cx:float, cy:float): 158 ''' 座標(cx, cy)を中心に拡大縮小 ''' 159 160 # 原点へ移動 161 self.translate(-cx, -cy) 162 # 拡大縮小 163 self.scale(scale) 164 # 元に戻す 165 self.translate(cx, cy) 166 167 def zoom_fit(self, image_width, image_height): 168 '''画像をウィジェット全体に表示させる''' 169 170 # キャンバスのサイズ 171 canvas_width = self.canvas.winfo_width() 172 canvas_height = self.canvas.winfo_height() 173 174 if (image_width * image_height <= 0) or (canvas_width * canvas_height <= 0): 175 return 176 177 # アフィン変換の初期化 178 self.reset_transform() 179 180 scale = 1.0 181 offsetx = 0.0 182 offsety = 0.0 183 184 if (canvas_width * image_height) > (image_width * canvas_height): 185 # ウィジェットが横長(画像を縦に合わせる) 186 scale = canvas_height / image_height 187 # あまり部分の半分を中央に寄せる 188 offsetx = (canvas_width - image_width * scale) / 2 189 else: 190 # ウィジェットが縦長(画像を横に合わせる) 191 scale = canvas_width / image_width 192 # あまり部分の半分を中央に寄せる 193 offsety = (canvas_height - image_height * scale) / 2 194 195 # 拡大縮小 196 self.scale(scale) 197 # あまり部分を中央に寄せる 198 self.translate(offsetx, offsety) 199 200 # ------------------------------------------------------------------------------- 201 # 描画 202 # ------------------------------------------------------------------------------- 203 204 def draw_image(self, pil_image): 205 206 if pil_image == None: 207 return 208 209 # キャンバスのサイズ 210 canvas_width = self.canvas.winfo_width() 211 canvas_height = self.canvas.winfo_height() 212 213 # キャンバスから画像データへのアフィン変換行列を求める 214 #(表示用アフィン変換行列の逆行列を求める) 215 mat_inv = np.linalg.inv(self.mat_affine) 216 217 # PILの画像データをアフィン変換する 218 dst = pil_image.transform( 219 (canvas_width, canvas_height), # 出力サイズ 220 Image.AFFINE, # アフィン変換 221 tuple(mat_inv.flatten()), # アフィン変換行列(出力→入力への変換行列)を一次元のタプルへ変換 222 Image.NEAREST, # 補間方法、ニアレストネイバー 223 fillcolor= self.back_color 224 ) 225 226 # 表示用画像を保持 227 self.image = ImageTk.PhotoImage(image=dst) 228 229 230 # 画像の描画 231 item = self.canvas.create_image( 232 0, 0, # 画像表示位置(左上の座標) 233 anchor='nw', # アンカー、左上が原点 234 image=self.image # 表示画像データ 235 ) 236 237 238 239 def redraw_image(self): 240 ''' 画像の再描画 ''' 241 if self.pil_image == None: 242 return 243 self.draw_image(self.pil_image) 244 245 246if __name__ == "__main__": 247 root = tk.Tk() 248 app = Application(master=root) 249 app.mainloop() 250

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Pythonで処理前後の画像を並べてGUIに表示して、パラメータによる画像変化がダイナミックにわかるに複数画像の表示のプログラムがあります。これを参考にして、拡大縮小移動ができるようにすればできると思います。

投稿2022/01/17 11:12

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問