HyperAI超神経
Back to Headlines

Pythonで現代的なGUIアプリケーションを構築:ウェブカメラ映像にインタラクティブなフィルターを適用する方法

21日前

Pythonを使った現代的なGUIによるコンピュータビジョンアプリケーション 概要 本記事では、OpenCVとCustomTkinterを使ってWebカメラ映像にフィルターを適用し、リアルタイムで表示するシンプルなGUIアプリケーションの開発方法を紹介します。このアプリケーションでは、ユーザーがさまざまなフィルターを選び、画像処理パイプラインを迅速かつ直感的に調整することができます。 手順 基本のOpenCV GUI Webカメラからフレームを読み取り、OpenCVのウィンドウに表示するシンプルなループを作成します。 キーボード入力を利用することで、グレースケールやブラーなどのフィルターを選択できます。 シェルスクリプトを使用して環境をセットアップします。 sh uv add numpy opencv-python pillow customtkinter キーボード入力でのフィルター切替 キーボード入力を追加することで、異なるフィルターを選択できるようにします。数字キーで切り替えることが可能です。 選択したフィルターの名前を画像の下部に表示することで、ユーザーがどのフィルターを适用しているか確認できるようにします。 スライダーの追加 OpenCVのトラックバー機能を使って、より便利なUI要素を追加します。 トラックバーの位置によって選択されるフィルターが変更されます。 modernなGUIの構築 CustomTkinterを使い、より現代的なデザインとユーザーエクスペリエンスのあるアプリケーションを構築します。 アプリケーションの基本骨格を作ります。左側にはフィルター選択用のラジオボタンを配置し、右側には画像表示用のフレームを配置します。 カスタム画像表示コンポーネント CustomTkinterのCTkLabelをベースに、OpenCVのフレームを表示するカスタムコンポーネントCTkImageDisplayを作成します。 OpenCV形式のフレームをPillowのImageオブジェクトに変換し、CTkImageを使って表示します。 フレームの更新 afterメソッドを使って、定期的に新しいフレームを表示する関数update_frameを呼び出します。 この関数では、選択されたフィルターに対応する処理を適用します。 マルチスレッディングと同期 主なグラフィカルユーザーインターフェース(UI)の処理を別スレッドで実行し、フレームの更新をキューを使って同期します。 UIスレッドと画像処理スレッドの競合を避けるために、キューを使用してデータを安全に転送します。 具体的なコード例 ```python import cv2 import customtkinter import threading import queue import numpy as np from PIL import Image class CTkImageDisplay(customtkinter.CTkLabel): def init(self, master): self._textvariable = customtkinter.StringVar(master, "Loading...") super().init(master, textvariable=self._textvariable, image=None) def set_frame(self, frame): target_width, target_height = frame.shape[1], frame.shape[0] frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame_pil = Image.fromarray(frame_rgb, "RGB") ctk_image = customtkinter.CTkImage( light_image=frame_pil, dark_image=frame_pil, size=(target_width, target_height), ) self.configure(image=ctk_image, text="") self._textvariable.set("") class App(customtkinter.CTk): def init(self): super().init() self.title("Webcam Stream") self.geometry("800x600") self.filter_var = customtkinter.IntVar(value=0) filter_types = [ "normal", "grayscale", "blur", "threshold", "canny", "sobel", "laplacian", ] # フィルター選択用フレーム self.filters_frame = customtkinter.CTkFrame(self) self.filters_frame.pack(side="left", fill="both", expand=False, padx=10, pady=10) for filter_id, filter_type in enumerate(filter_types): rb_filter = customtkinter.CTkRadioButton( self.filters_frame, text=filter_type.capitalize(), variable=self.filter_var, value=filter_id, ) rb_filter.pack(padx=10, pady=10) if filter_id == 0: rb_filter.select() # 画像表示用フレーム self.image_frame = customtkinter.CTkFrame(self) self.image_frame.pack(side="right", fill="both", expand=True, padx=10, pady=10) self.image_display = CTkImageDisplay(self.image_frame) self.image_display.pack(fill="both", expand=True, padx=10, pady=10) self.queue = queue.Queue(maxsize=1) self.webcam_thread = threading.Thread(target=self.run_webcam_loop, daemon=True) self.webcam_thread.start() self.frame_loop_dt_ms = 16 self.after(self.frame_loop_dt_ms, self._update_frame) def _update_frame(self): try: frame = self.queue.get_nowait() self.image_display.set_frame(frame) except queue.Empty: pass self.after(self.frame_loop_dt_ms, self._update_frame) def run_webcam_loop(self): self.cap = cv2.VideoCapture(0) if not self.cap.isOpened(): return while True: ret, frame = self.cap.read() if not ret: break filter_id = self.filter_var.get() filter_type = filter_types[filter_id] if filter_type == "grayscale": frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) elif filter_type == "blur": frame = cv2.GaussianBlur(frame, ksize=(15, 15), sigmaX=0) elif filter_type == "threshold": gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) _, frame = cv2.threshold(gray, thresh=127, maxval=255, type=cv2.THRESH_BINARY) elif filter_type == "canny": frame = cv2.Canny(frame, threshold1=100, threshold2=200) elif filter_type == "sobel": frame = cv2.Sobel(frame, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=5) elif filter_type == "laplacian": frame = cv2.Laplacian(frame, ddepth=cv2.CV_64F) elif filter_type == "normal": pass if frame.dtype != np.uint8: cv2.normalize(frame, frame, 0, 255, cv2.NORM_MINMAX) frame = frame.astype(np.uint8) if len(frame.shape) == 2: frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR) self.queue.put(frame) app = App() app.mainloop() ``` 結果 このアプローチにより、Webカメラからのリアルタイム映像にさまざまなフィルターを適用し、ユーザーが直感的に選択と調整を行うことが可能になりました。 CustomTkinterの使用によって、ModernなUIの構築が容易になり、ユーザーエクスペリエンスが大幅に向上しています。 業界関係者のコメント 「このようなGUIアプリケーションの開発は、コンピュータビジョン分野におけるイテレーションの速度を大幅に向上させることができます。ユーザーが視覚的なフィードバックを得て、即座に調整できるようになったことで、開発過程が非常に効率的になりました。」 — コンピュータビジョンエンジニア 会社概要 CustomTkinterは、高品質でModernなTkinterベースのGUIアプリケーションを開発するためのライブラリです。OpenCVとの組み合わせにより、視覚的なフィードバックが必要な画像処理アプリケーションの開発が容易になります。 ご参考にどうぞ。

Related Links