2021年1月26日火曜日

OpenCVのウィンドウを画面外に出ないようにする

OpenCVで表示されたウィンドウをマススによるサイズ変更を許しながら画面外に出るのを防ぐ方法のメモ. この方法はWindows限定でPythonでの実装方法.

必要なライブラリはOpenCVとWindowsのAPIに関するもの.

import cv2
import win32gui
import win32con
import ctypes

WindowsのAPIを用いて画面サイズを取得する.

# 画面のサイズ取得
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
(sw, sh) = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))

画像(test.png)を一旦imshowで表示してその画像の解像度とウィンドウハンドル(hwnd)を取得しておく.

# ウィンドウの準備
frame = cv2.imread("test.jpg")
window_name = "Locate Window"
cv2.namedWindow(window_name,  cv2.WINDOW_NORMAL)
cv2.imshow(window_name,frame)
hwnd = win32gui.GetActiveWindow()
flag = win32con.SWP_NOSIZE | win32con.SWP_NOZORDER

マウスでウィンドウサイズを自由に変更できるけど,while文内でウィンドウサイズを修正する.

while True: 
    # ウィンドウが画面外にあれば修正する
    (x0, y0, x1, y1) = win32gui.GetWindowRect(hwnd)
    if x0 < 0:
        x0 = 0
    if x1 > sw:
        x0 -= x1 - sw
    if y0 < 0:
        y0 = 0
    if y1 > sh:
        y0 -= y1 - sh
        
    #ここでウィンドウ位置を修正
    win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, x0, y0, x1-x0+1, y1-y0+1, flag)
	
    # 座標を表示(無くてもいい)
    text = "window: (%d, %d)-(%d, %d), screen: (%d, %d)" % (x0, y0, x1, y1, sw, sh)
    frame_disp = frame.copy()
    cv2.putText(frame_disp, text, (10, 40), cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 255, 255), 3, cv2.LINE_AA)
    cv2.putText(frame_disp, text, (10, 40), cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (0, 0, 0), 1, cv2.LINE_AA)
    cv2.imshow(window_name, frame_disp)

    # Enterキーで終了
    if cv2.waitKey(1) == 13:
        break