前提
Pythonで特定のウィンドウをキャプチャして画像処理を施したものをtkinterのウィンドウに表示するアプリケーションを製作しています。
実現したいこと
- 指定したウィンドウのキャプチャ
- キャプチャした画像の処理
- 画像をtkinterで表示
発生している問題
・ImageGrab.grab()で取得した画像に処理を加えてcv2.imshow()で表示する事はできたがディスプレイ全体のスクリーンショットしか出来ない所為で合わせ鏡の様に延々と暗くなってしまう。理想としてはchromeやZoomなど実行中のアプリケーションを指定してそのウィンドウだけをキャプチャしたい。最前面に出す必要が無ければなおよし。
・処理もWhile文で回しているだけなので使い勝手が悪い。
・生成したウィンドウサイズも変えられない。
基本のソースコード
Python
1from PIL import ImageGrab 2import numpy as np 3import cv2 4 5print("--- Running Now ---") 6 7while True: 8 # スクリーンキャプチャ 9 img = ImageGrab.grab() 10 11 # PILのimageをndarrayに変換 12 cv_img = np.array(img, dtype=np.uint8) 13 14 # 色変換 15 cv_img = cv2.cvtColor(cv_img, cv2.COLOR_RGB2BGR) 16 17 hsv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2HSV) 18 s_magnification = 4 # 彩度(Saturation)の倍率 19 v_magnification = 0.4 # 明度(Value)の倍率 20 hsv_img[:,:,(1)] = hsv_img[:,:,(1)]*s_magnification # 彩度の計算 21 hsv_img[:,:,(2)] = hsv_img[:,:,(2)]*v_magnification # 明度の計算 22 img_bgr = cv2.cvtColor(hsv_img,cv2.COLOR_HSV2BGR) # 色空間をHSVからBGRに変換 23 24 # 画面表示 25 cv2.imshow('figure',img_bgr) 26 cv2.waitKey(1)
試したこと
このサイトを参考にWhile文に頼らず実行したい時間だけキャプチャし続ける様にしたかったが、カメラ情報を無理やりキャプチャ画像に入れ替えただけな所為で失敗。表示ウィンドウのサイズに関してはこれが実現できれば達成。
指定したウィンドウのキャプチャは未だに良い方法が浮かばず。
Python
1import tkinter as tk 2from tkinter import filedialog 3from PIL import Image, ImageTk, ImageOps # 画像データ用 4from PIL import ImageGrab 5import numpy as np 6 7import cv2 8 9class Application(tk.Frame): 10 def __init__(self, master = None): 11 super().__init__(master) 12 self.pack() 13 14 self.master.title("OpenCVの動画表示") # ウィンドウタイトル 15 self.master.geometry("400x300") # ウィンドウサイズ(幅x高さ) 16 17 # Canvasの作成 18 self.canvas = tk.Canvas(self.master) 19 # Canvasにマウスイベント(左ボタンクリック)の追加 20 self.canvas.bind('<Button-1>', self.canvas_click) 21 # Canvasを配置 22 self.canvas.pack(expand = True, fill = tk.BOTH) 23 24 # カメラをオープンする 25 img = ImageGrab.grab() 26 self.capture = np.array(img, dtype=np.uint8) 27 28 self.disp_id = None 29 30 def canvas_click(self, event): 31 '''Canvasのマウスクリックイベント''' 32 33 if self.disp_id is None: 34 # 動画を表示 35 self.disp_image() 36 else: 37 # 動画を停止 38 self.after_cancel(self.disp_id) 39 self.disp_id = None 40 41 def disp_image(self): 42 '''画像をCanvasに表示する''' 43 44 # フレーム画像の取得 45 ret, frame = self.capture 46 47 # BGR→RGB変換 48 cv_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 49 50 hsv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2HSV) 51 s_magnification = 4 # 彩度(Saturation)の倍率 52 v_magnification = 0.4 # 明度(Value)の倍率 53 hsv_img[:,:,(1)] = hsv_img[:,:,(1)]*s_magnification # 彩度の計算 54 hsv_img[:,:,(2)] = hsv_img[:,:,(2)]*v_magnification # 明度の計算 55 img_bgr = cv2.cvtColor(hsv_img,cv2.COLOR_HSV2BGR) # 色空間をHSVからBGRに変換 56 57 # NumPyのndarrayからPillowのImageへ変換 58 pil_image = Image.fromarray(img_bgr) 59 60 # キャンバスのサイズを取得 61 canvas_width = self.canvas.winfo_width() 62 canvas_height = self.canvas.winfo_height() 63 64 # 画像のアスペクト比(縦横比)を崩さずに指定したサイズ(キャンバスのサイズ)全体に画像をリサイズする 65 pil_image = ImageOps.pad(pil_image, (canvas_width, canvas_height)) 66 67 # PIL.ImageからPhotoImageへ変換する 68 self.photo_image = ImageTk.PhotoImage(image=pil_image) 69 70 # 画像の描画 71 self.canvas.create_image( 72 canvas_width / 2, # 画像表示位置(Canvasの中心) 73 canvas_height / 2, 74 image=self.photo_image # 表示画像データ 75 ) 76 77 # disp_image()を10msec後に実行する 78 self.disp_id = self.after(10, self.disp_image) 79 80if __name__ == "__main__": 81 root = tk.Tk() 82 app = Application(master = root) 83 app.mainloop()
ValueError: too many values to unpack (expected 2)
補足情報(FW/ツールのバージョンなど)
開発にはVScodeを使用しています。

回答1件
あなたの回答
tips
プレビュー