pythonで業務効率化/RPA自作 – 検討 その5 マルチモニタ環境での画面全体の取得方法

python
スポンサーリンク

ちまたで話題のRPA(Robotic Process Automation)をpythonで自作することで、業務効率化はもちろん、必要に応じて内製でカスタマイズできるシステム作成を目指します。

今回は使えそうなライブラリ PyWin32 の検証をしていきます。

-- 実行環境 --
Windows 10 64ビット版(1903)、python 3.7.4

スポンサーリンク

現状の問題点

画像のマッチングに PyAutoGUI および OpenCV を試してきましたが、どちらも複数台モニタが接続された環境で正常に処理が行えませんでした。(メインモニタ内のみ画像取得・マッチング処理が行われるため、サブモニタは全く処理できない状況)

当然ながら、今時マルチモニタなんて珍しくもなく、シングルモニタでしか使えないというのは微妙感満載でしたので、今回はマルチモニタ環境でも全モニタ画像が取得でき、かつマッチングできる方法をご紹介します。

デバイスコンテキスト

デバイスコンテキストとはWindowsが提供しているグラフィックス描画機能「Graphics Device Interface」(GDI)が管理するデータ構造で,メモリ上に格納されています。
下記

マルチモニタの画像取得

マルチモニタでもモニタ全体を取得し、画像化するサンプルです。デスクトップのハンドルからデバイスコンテキストを取得。取得したデバイスコンテキストからディスプレイの情報を空のビットマップにコピー/取得の流れとなっています。

import win32api
import win32gui
import win32ui
import win32con

import numpy as np
import cv2

#==================================================================
# デスクトップのキャプチャ取得(マルチモニタ対応)
#==================================================================
def get_capture(flag_gray: bool = True):
	try:
		# デスクトップ全体サイズ取得
		vscreenwidth = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
		vscreenheigth = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
		vscreenx = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
		vscreeny = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
		width = vscreenx + vscreenwidth
		height = vscreeny + vscreenheigth
	
		# デスクトップのデバイスコンテキスト取得
		hwnd = win32gui.GetDesktopWindow() 
		windc = win32gui.GetWindowDC(hwnd)
		srcdc = win32ui.CreateDCFromHandle(windc)
		memdc = srcdc.CreateCompatibleDC()

		# デバイスコンテキストからピクセル情報コピー、bmp化
		bmp = win32ui.CreateBitmap()
		bmp.CreateCompatibleBitmap(srcdc, width, height)
		memdc.SelectObject(bmp)
		memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)

		# イメージ取得/調整
		img = np.frombuffer(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
		if flag_gray is True :
			img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

		# 解放
		srcdc.DeleteDC()
		memdc.DeleteDC()
		win32gui.ReleaseDC(hwnd, windc)
		win32gui.DeleteObject(bmp.GetHandle())

		return img
	
	except Exception as err:
		# 取得失敗
		return None

# 処理
img = get_capture( False)
cv2.imwrite(r'desktop.png', img)

実行結果

左が23.8 インチモニタ、右が20.1インチモニタ。解像度は左右共に1920×1080の環境で取得した結果画像です。複数台のモニタ画像が取得できていることが分かります。インチの差異がわずかに画面サイズの違いとして確認できます。

できるUiPath 実践RPA [ 清水理史 ]
楽天ブックス
¥ 2,200(2020/11/06 18:51時点)

まとめ

今回はマルチモニタ環境で全モニタ画像をPyWin32 のモジュールを使って取得する方法をご紹介しました。サンプルでは取得した画像を保存していますが、今回の目的であるRPAでは取得画像とターゲット画像を使用してマッチングを行うことでどちらの画面にターゲットがあってもヒットさせることが出来る事になります。

注意点として、画像取得方法等からマッチングを行うための前提条件が満たせない場合があり得ます。その際はエラー内容を確認の上、画像の調整を行ってください。
私がテストした環境ではチャンネル数だけ合わせれば別PCで取得した画像などでもほぼマッチング可能でした。

今回はご覧頂きありがとうございました。

コメント

タイトルとURLをコピーしました