【完成版】特定のウィンドウだけの動画とGIFを保存したい (Python デスクトップキャプチャ2)
本日の課題と目標
録画時間と待機時間を自由に変更できるようにする
保存するウィンドウの名前を指定できるようにする
はじめに
前回作成したデスクトップ画面を録画するプログラムを改良します。録画が始まるタイミングと終わったタイミングがわかるようにしました。
プログラムのコード
import cv2 import numpy as np from PIL import ImageGrab import ctypes import win32gui import tkinter import time # ウィンドウのタイトル名 root = tkinter.Tk() root.title('test') root.geometry('300x450') # キャンバスエリアの設定 canvas = tkinter.Canvas(root,width=300,height=450) canvas.pack() def Recording(): # 画面サイズを表示 canvas.create_text(150,360,text=str(x0)+', '+str(y0)+', '+str(x1)+', '+str(y1),font=('',12)) canvas.create_text(150,380,text=capSize,font=('',12)) # 録画時間(秒) movie_time = s2.get() # 開始時間の保存 sTime = time.time() # コーデックの設定 今回は.mp4 fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 動画保存用 writer = cv2.VideoWriter('SC.mp4', fourcc, 10, capSize) # gif用 images = [] # FPSのカウント用 1度だけ count = 0 FirstFlag = True # writerが開いている間、ループ while (writer.isOpened()): root.update() # PIL Image から numpy配列 に変換してから書き込み img_bgr = np.asarray(ImageGrab.grab(bbox=(x0, y0, x1, y1))) img_rgb = img_bgr[:, :, [2, 1, 0]] # BGR -> RGB順に writer.write(img_rgb) # gif用 images.append(ImageGrab.grab(bbox=(x0, y0, x1, y1))) # FPS取得 1度だけ if FirstFlag: count += 1 # 開始から1秒たったら、そのときのcountをFPSとする if time.time() - sTime > 1.0: writer.set(cv2.CAP_PROP_FPS, count) canvas.create_text(150,400,text="FPS: {}".format(count),font=('',12)) FirstFlag = False # 開始から録画時間(秒)で終了 if time.time() - sTime > movie_time: break # gifファイルを保存 images[0].save('gif_date.gif',save_all=True,append_images=images[1:],optimize=False,duration=100,loop=0) # writerの解放 -> 保存 writer.release() # 録画終了を表示 canvas.delete('Time') canvas.create_text(150,40,text='録画終了',font=('Helvetica',30,'bold'),tag='Time') canvas.create_text(150,210,text=s2.get(),font=('Helvetica',24,'bold'),tag='Time') canvas.create_text(150,420,text='O K',font=('',12)) def on_Scale(self): # 図形の削除 canvas.delete('Time') # 初期タイムの変更 canvas.create_text(150,40,text=s1.get(),font=('Helvetica',30,'bold'),tag='Time') canvas.create_text(150,210,text=s2.get(),font=('Helvetica',24,'bold'),tag='Time')
def startButtonClick(): # グローバル変数の設定 global endTime global capSize global x0, y0, x1, y1 endTime=time.time() + s1.get() #root.after(50,update) update() # ウィンドウの名前 window_name = EditBox.get() process_list = []
def callback(handle, _): process_list.append(win32gui.GetWindowText(handle))
win32gui.EnumWindows(callback, None) # ターゲットウィンドウ名を探す for process_name in process_list: if window_name in process_name: hnd = win32gui.FindWindow(None, process_name) break else: # 見つからなかったら画面全体を取得 hnd = win32gui.GetDesktopWindow() # ウィンドウサイズ取得 x0, y0, x1, y1 = win32gui.GetWindowRect(hnd) x0 += 7 x1 -= 7 y1 -= 7 width = x1 - x0 height = y1 - y0 capSize = (width, height) def update(): # 図形の削除 canvas.delete('Time') elapsedTime=endTime-time.time() if elapsedTime > 0: # 残り時間を0になるまで表示 canvas.create_text(150,40,text=round(elapsedTime,1),font=('Helvetica',30,'bold'),tag='Time') canvas.create_text(150,210,text=s2.get(),font=('Helvetica',24,'bold'),tag='Time') root.after(50,update) else: # 残り時間が0になれば「録画中」を表示 canvas.create_text(150,40,text='録画中',font=('Helvetica',30,'bold'),tag='Time',fill='red') canvas.create_text(150,210,text=s2.get(),font=('Helvetica',24,'bold'),tag='Time') # 録画の開始 Recording() # 初期タイムを設定 var1 = tkinter.IntVar(master=root,value=3,) var2 = tkinter.IntVar(master=root,value=5,) # スケール(スライダー)の作成 s1 = tkinter.Scale(root,orient='h',showvalue=False,variable=var1,from_=1,to=10,length=160,command=on_Scale) s1.place(x=70, y=68) s2 = tkinter.Scale(root,orient='h',showvalue=False,variable=var2,from_=1,to=60,length=160,command=on_Scale) s2.place(x=70, y=230) # ボタンを作成 b = tkinter.Button(root,text='スタート',width=8,font=("",14),command=startButtonClick) b.place(x=110, y=100) # テキストを作成 canvas.create_text(150,40,text=s1.get(),font=('Helvetica',30,'bold'),tag='Time') canvas.create_text(150,210,text=s2.get(),font=('Helvetica',24,'bold'),tag='Time') canvas.create_text(150,180,text='録画時間',font=('',12)) # テキストボックスを作成 canvas.create_text(150,280,text='ウィンドウの名前',font=('',12)) EditBox = tkinter.Entry(width=20, font=('',14)) EditBox.insert(tkinter.END,'test') EditBox.place(x=50, y=300) root.mainloop()
解説
改良点
# gifファイルを保存
images[0].save('gif_date.gif', save_all=True, append_images=images[1:], optimize=False, duration=100, loop=0)
「duration」各フレームの表示時間(単位はミリ秒)を60から100に変更して録画時間がより正確になりました。
プログラムの流れ
はじめに待機時間(1~10秒)、録画時間(1~60秒)、ウィンドウの名前(検索ワード)を決めて「スタート」ボタンを押すと待機時間が経過したあと録画が始まります。
今開いている全てのウィンドウの中からタイトル名に検索文字が含まれてるウィンドウを1つ探して位置と大きさの情報を取得します。
その範囲の画像データを時間ごとに記録して指定の時間が経過したら動画ファイルとGIFファイルにして保存します。
参考サイト
保存ファイル
lesson42.py
文責:Luke