パソコンの画面を録画する
パソコンの画面を録画して動画ファイルに保存します。ライブラリPyAutoGUIを使うとパソコン画面のスクリーンショットを取得できます。スクリーンショット画像を連続して取得し、OpenCVで動画ファイルに書き込むことで画面操作を録画します。PyAutoGUIのスクリーンショットではマウスカーソルが消えてしまうので 、PyAutoGUIでマウスの現在位置を取得しその位置にマウスカーソルの絵を描いています。
環境
- windows10 home
- Anaconda 3/ jupyter notebook 6.4.6
- Python 3.8.12
- pyautogui 0.9.53
- numpy 1.21.5
- OpenCV 4.5.5
コード
パソコンの画面サイズは1920x1080ですが画面下のタスクバーを消したいのでキャプチャーサイズを1920x1030としています。動画のレートは15FPS、録画時間を10秒に設定しています。画像一枚ごとの取得時間を計測しそれが1/FPS(15FPSの場合は0.0667秒)よりも小さい場合、時間合わせのためスリープを入れています。環境によると思いますが私のパソコンでは15FPSで実際の処理時間とトントン(スリープが入ったり入らなかったり)、25FPSでは処理が間に合いませんでした。間に合わない場合、例えば20秒の録画時間が10秒の動画となり早送りになってしまいます。
また、プログラムを実行して少し経ってから録画を開始するため初めに3秒間スリープしています。
import time import pyautogui import cv2 import numpy as np # 3秒スリープ time.sleep(3) # 動画のフレームレート fps=15 # 録画時間(秒) rec_sec = 10 # キャプチャー領域 cap_region = (0,0, 1920, 1030) # キャプチャー画像を格納するリスト frames = [] #画面をキャプチャーし for i in range(int(fps*rec_sec)): # 処理開始時間の取得 start = time.perf_counter() # 画面をキャプチャー cap = pyautogui.screenshot(region = cap_region) # pillow形式からOpenCV形式に変換 img = cv2.cvtColor(np.array(cap), cv2.COLOR_RGB2BGR) # マウス位置を取得しマウスの絵を描画 mx, my = pyautogui.position() pts = np.array([[mx, my], [mx, my+25], [mx+5, my+20], [mx+10, my+28],[mx+14, my+27],[mx+11, my+20], [mx+20, my+20]]) cv2.polylines(img, [pts], True, 30, thickness=1) # リストにキャプチャー画像を追加 frames.append(img) # 処理終了時間の取得 end = time.perf_counter() # 1回の処理時間が1フレームより短い場合、不足分スリープ if end-start<1/fps: time.sleep(1/fps-(end-start)) # 保存用動画ファイルのフォーマット設定 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('capture.mp4', fourcc, fps, (1920, 1030)) # キャプチャー画像を読み出して出力動画ファイルに追記 for img in frames: out.write(img) out.release() # 出力動画ファイルをクローズ
実行結果
画面を録画した動画ファイルが保存されます。
(下はサイズを縮小してアニメーションGIFに変換したもの)
以下のサイトを参考にさせていただきました
機械系エンジニアの備忘録 > 【python】デスクトップ画面をキャプチャ(録画)する簡易ソフトを作る
白猫学生のブログ > マウスカーソルの現在の座標の取得方法
ブログランキングに参加しています
動画を鉛筆画風に変換する
動画を鉛筆画に変換します。画像処理ライブラリOpenCVの cv2.VideoCapture で動画ファイルを読み出し各フレームをcv2.pencilSketchで鉛筆画に変換し動画に保存します。1.5秒までは元動画、1.5秒~3秒はcv2.addWeightedで元動画から鉛筆画に徐々に変化させ、3秒以降を鉛筆画にしています。
環境
準備
動画ファイルはMixkitの 'Cute old couple in a park' をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名 ’couple.mp4' で保存しました(動画のフレームサイズは480x270)。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。
コード
from PIL import Image import cv2 import numpy as np # gifファイル作成用イメージリスト images =[] # 動画ファイル作成用イメージリスト frames =[] # 動画ファイルのキャプチャー cap = cv2.VideoCapture('couple.mp4') # フレームの幅取得 width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # フレームの高さ取得 height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 総フレーム数取得 allframes = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 動画ファイルのフレームレート取得 fps = cap.get(cv2.CAP_PROP_FPS) # 保存用動画ファイルのフォーマット設定 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('pencil.mp4', fourcc, fps, (int(width), int(height))) # 動画を1コマずつ取り込んで処理 while(cap.isOpened()): ret, frame = cap.read() # キャプチャー画像の取り込み if ret==True: # キャプチャー画像がある場合 # 現在時間を取得 time = cap.get(cv2.CAP_PROP_POS_MSEC) # 鉛筆画変換 dst1, dst2 = cv2.pencilSketch(frame) # 1500msまでは元の画像 if time<1500: img = frame # 1500-3000msは元の画像と鉛筆画のブレンド if time>=1500 and time<=3000: alpha = 1-(time-1500)/1500 beta = 1-alpha img = cv2.addWeighted(frame, alpha, dst2, beta, 0) # 3000msからは鉛筆画 if time>3000: img = dst2 # VideoWriterにフレームを追加 out.write(img) # gifファイル作成用イメージリストにフレームを追加 images.append(Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))) else: # キャプチャー画像がない場合はループ終了 break cap.release() # 再生画像をクローズ out.release() # 出力動画ファイルをクローズ # gif動画保存 images[0].save('pencil.gif', save_all=True, append_images=images[1:], optimize=False, duration=1000/fps, loop=0)
実行結果
鉛筆画に変換された動画が保存されます。
以下のサイトを参考にさせていただきました
Emotion Explorer > Python 鉛筆画風 PNGアニメーションを作成
Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
ブログランキングに参加しています
複数の動画に字幕を付けて1つの動画にまとめる
複数の動画を1つの動画にまとめます。また各動画の説明用字幕を付けます。画像処理ライブラリOpenCVの cv2.VideoCapture で各動画の先頭から3秒まで読みだし、画像処理ライブラリPillowのdraw.textで字幕を付けます。字幕が徐々に現れて徐々に消えるように見せるため、元の動画から読みだした画像とアルファ値を持たせた字幕用画像を、字幕用画像のアルファ値を変えながらPillowのImage.alpha_compositeで合成しています。
環境
準備
Mixkitから3つの動画をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'movies'を作りその中にファイル名 ’01.mp4', ’02.mp4', ’03.mp4' で保存しました。
White sand beach and palm trees
Black scorpion walking closeup
Fly over a huge canyon covered in vegetation
コード
はじめにmoviesフォルダに含まれるファイルをリストにし、動画をひとつづつ読みだします。cv2.VideoCaptureで動画を取り込み、cap.get(cv2.CAP_PROP_POS_MSEC)で現在の時間を調べ3000msまで取り込みます。字幕用画像のアルファ値を
~1000ms:0から徐々に増える
1000~2000ms:一定の値(220)
2000ms~:0まで徐々に減る
として字幕が表れて消える効果を表現しています。
動画読み出しと動画書き出しをOpenCVで行いますが、字幕の書き込みは日本語が描けるPillowで行うためOpenCV⇔Pillowで画像を受け渡す際には画像フォーマットの変換を行います。
動画はmp4ファイルで書き出すとともに、このブログに貼るためにgifアニメーションも作成しています。
import os from PIL import Image, ImageDraw, ImageFont import cv2 import numpy as np # moviesフォルダ内のファイルをリストに files = os.listdir('movies/') # gifファイル作成用イメージリスト images =[] # 動画ファイル作成用イメージリスト frames =[] # 字幕のリスト subtitles =[ '白い砂浜の南国のビーチ', '森を進む黒いサソリ', '森に囲まれたロッキー渓谷' ] # 字幕のアルファ値(不透明度)の最大値 amax = 220 # 保存用動画ファイルのフォーマット設定 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('subtitles.mp4', fourcc, 25.0, (384, 216)) # 動画ファイルをひとつずつ読みだして処理 for i in range(3): movie = files[i] subtitle = subtitles[i] # 動画ファイルのキャプチャー cap = cv2.VideoCapture('movies/'+movie) while(cap.isOpened()): # キャプチャー画像の取り込み ret, frame = cap.read() # 現在時間を取得 time = cap.get(cv2.CAP_PROP_POS_MSEC) # キャプチャー画像があって3000msec以内の場合 if ret==True and time<3000: # 384x216にリサイズ resize = cv2.resize(frame, (384, 216)) # 画像をcv2形式からPillow形式に変換しアルファチャンネルを追加 im = Image.fromarray(cv2.cvtColor(resize, cv2.COLOR_BGR2RGB)) im.putalpha(255) # 字幕のアルファ値設定 if time < 1000: alpha = int(amax*time/1000) elif time > 2000: alpha = int(amax*(3000-time)/1000) else: alpha = amax # 字幕用画像に字幕を縁取り文字で描画 im2 = Image.new('RGBA', (384, 216), (0, 0, 0, 0)) draw = ImageDraw.Draw(im2) font = ImageFont.truetype('C:\Windows\Fonts\BIZ-UDGothicB.ttc', 24) draw.text((40, 180), subtitle, fill=(255, 255, 255, alpha), font=font, stroke_width=1, stroke_fill=(150, 150, 150, alpha)) # 動画のフレームと字幕用画像の合成 comp = Image.alpha_composite(im, im2) # gifファイル作成用イメージリストにフレームを追加 images.append(comp) # Pillow形式からcv2形式に変換 img = cv2.cvtColor(np.array(comp), cv2.COLOR_RGB2BGR) # VideoWriterにフレームを追加 out.write(img) else: # キャプチャー画像がない場合はループ終了 break # 再生画像をクローズ cap.release() # 出力動画ファイルをクローズ out.release() # gif動画保存 images[0].save('subtitles.gif', save_all=True, append_images=images[1:], optimize=True, duration=40, loop=0)
実行結果
3つの動画が字幕を付けて1つの動画にまとめられました。
以下のサイトを参考にさせていただきました
Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【Pillow】アルファチャンネル付き図形と画像の合成
ブログランキングに参加しています
Yahooニュース・アクセスランキングの見出しを取得し合成音声で読み上げる(Windows)
Yahooニュース・アクセスランキングの見出しをスクレイピングで取得し、それを合成音声で読み上げます。
pywin32(win32com)はPythonからWindowsアプリケーションを制御するためのライブラリです。win32comでWindows標準の音声合成機能Microsoft Speech API(SAPI)を制御することで任意の文章を音声合成できます。
関連記事
Yahooニュース・アクセスランキングの見出しを取得し頻出単語を調べる
環境
- windows10 home
- Anaconda 3/ jupyter notebook 6.4.6
- Python 3.8.12
- requests 2.27.1
- beautifulsoup4 4.10.0
- pywin32 303
コード
requestでYahooニュース・アクセスランキングのページを取得しBeautifulSoupで分析します。BeautifulSoupオブジェクトを見るとニュースのタイトルは classが 'newsFeed_item_title' となっていたため、そのclassを抽出し文字列に変換後 'Sapi.SpVoice' に渡して合成音声で読み上げます。読み上げ速度を少し遅くするためRate=-1としています(-10~10で設定可能)。
import requests from bs4 import BeautifulSoup as bs import win32com.client # アプリケーション'Sapi.SpVoice'をオブジェクトspeechに適用 speech = win32com.client.Dispatch('Sapi.SpVoice') # 読み上げ速度は少しゆっくり speech.Rate = -1 # Responseオブジェクトの取得 rs = requests.get('https://news.yahoo.co.jp/ranking/access?ty=t&c=c_int') # BeautifulSoupオブジェクトの取得 soup = bs(rs.text.encode(rs.encoding), 'html.parser') # class='newsFeed_item_title'のみ取得 selected_class = soup.select('.newsFeed_item_title') # タイトルを読み上げ for i in selected_class: speech.Speak(i.string)
実行結果
Yahooニュース・アクセスランキングの見出しが1位から順に合成音声で読み上げられます。
以下のサイトを参考にさせていただきました
sozorablog > 【Python初心者にオススメ】音声合成を使って好きな言葉(テキスト)をしゃべらせる(すぐにできます)
ブログランキングに参加しています
動画を途中からスローモーションにする
動画を途中からスローモーションにします。動画を読み出して、指定した時間以降で同じフレームを10コマ連続させて再び動画にすることでスローモーションにします。画像処理ライブラリOpenCVの cv2.VideoCapture で長さ5秒の動画ファイルを読み出し cv2.VideoWriter で動画に保存しますが4秒以降は同じフレームを10回繰り返します。
関連記事
環境
準備
動画ファイルはMixkitの 'Intense mixed martial arts combat between two women' をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名 ’boxing.mp4' で保存しました(動画のサイズは480x270)。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。
コード
cv2.VideoCaptureで動画を取り込み、4000ms以降は同じフレームを10回繰り返します。
from PIL import Image import cv2 # gifファイル作成用イメージリスト images =[] # 動画ファイル作成用イメージリスト frames =[] # 動画ファイルのキャプチャー cap = cv2.VideoCapture('boxing.mp4') # フレームの幅取得 width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # フレームの高さ取得 height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 総フレーム数取得 allframes = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 動画ファイルのフレームレート取得 fps = cap.get(cv2.CAP_PROP_FPS) # 保存用動画ファイルのフォーマット設定 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('slow.mp4', fourcc, fps, (int(width), int(height))) counter = 0 # 動画を1コマずつ取り込んで処理 while(cap.isOpened()): ret, frame = cap.read() # キャプチャー画像の取り込み if ret==True:# キャプチャー画像がある場合 # 現在時間を取得 time = cap.get(cv2.CAP_PROP_POS_MSEC) # 4秒を超えたらrepeatを10 if time > 4000 : repeat = 10 else: repeat = 1 for i in range(repeat): # VideoWriterにフレームを追加 out.write(frame) # gifファイル作成用イメージリストにフレームを追加 images.append(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))) else: # キャプチャー画像がない場合はループ終了 break cap.release() # 再生画像をクローズ out.release() # 出力動画ファイルをクローズ # gif動画保存 images[0].save('slow.gif', save_all=True, append_images=images[1:], optimize=True, duration=1000/fps, loop=0)
実行結果
ラストがスローモーションになった動画が保存されます。
]
以下のサイトを参考にさせていただきました
Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
ブログランキングに参加しています
動画からサムネイルを作る
動画から指定のフレームを切り出し文字を入れてサムネイルを作ります。動画ファイルを読み出しキャプチャーした画像の明度と彩度を強調し派手にしたうえで、縁取りの大きな文字で動画タイトルを入れます。画像のサイズをYoutube推奨カスタムサムネイルサイズの1280,x720にリサイズしてjpegで保存します。動画ファイルの読み出し、指定した秒数のフレームのキャプチャー、明度と彩度の強調は画像処理ライブラリOpenCVで行い、タイトル文字の描画とリサイズを画像処理ライブラリPillowで行います(OpenCVでは日本語を描画できないため)。
環境
準備
動画ファイルはMixkitの "Young people dancing intensely"をダウンロードし320x180にリサイズしたうえでjupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’dancing.mp4'で保存しました(フレームサイズ:1920x1080、 動画の長さ:18秒、フレームレート25:フレーム/秒) 。
コード
10秒15フレームを指定してサムネイルを作ります。
import cv2 from PIL import Image, ImageDraw, ImageFont import numpy as np # 動画ファイルのキャプチャー cap = cv2.VideoCapture('dancing.mp4') # 動画ファイルのフレームレート取得 fps = cap.get(cv2.CAP_PROP_FPS) # サムネイルにする秒、フレーム数指定(10秒15フレーム) target_sec = 14 target_frame = 12 target = (target_sec + target_frame/fps)*1000 # 設定した時間に移動 cap.set(cv2.CAP_PROP_POS_MSEC, target) # 画像のキャプチャー ret, frame = cap.read() # 再生画像をクローズ cap.release() # 変換用ルックアップテーブルの生成 gamma = 1.5 look_up_table = np.zeros((256, 1) ,dtype=np.uint8) for i in range(256): look_up_table[i][0] = (i/255)**(1.0/gamma)*255 # 色空間をBGR->HSVに変換 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # チャンネルごとに分割 h, s, v = cv2.split(hsv) # 明度(V)に対してルックアップテーブル適用 v_lut = cv2.LUT(v, look_up_table) # 彩度(S)に対してルックアップテーブル適用 s_lut = cv2.LUT(s, look_up_table) # H,変換後S,変換後Vをマージ merge = cv2.merge([h, s_lut, v_lut]) # HSV->BGR変換 bgr = cv2.cvtColor(merge, cv2.COLOR_HSV2BGR) # Pillow画像ファイルに変換 im = Image.fromarray(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)) # 縁取り文字の描画 draw = ImageDraw.Draw(im) font = ImageFont.truetype('C:\Windows\Fonts\BIZ-UDGothicB.ttc', 220) draw.text((800, 30), '話題の〇〇', fill=(250, 220, 0), font=font, stroke_width=12, stroke_fill=(0, 0, 0)) font = ImageFont.truetype('C:\Windows\Fonts\BIZ-UDGothicB.ttc', 210) draw.text((20, 830), 'みんなで踊ってみた', fill=(255, 0, 255), font=font, stroke_width=12, stroke_fill=(0, 120, 0)) # リサイズ resize = im.resize((1280, 720)) # 画像の保存 resize.save('thumbnail.jpg')
実行結果
10秒15フレームの画像に対して彩度明度を強調しタイトル文字を入れたサムネイル画像が1280,x720のjpegファイルで保存されます。
以下のサイトを参考にさせていただきました
PythonとRPAで遊ぶ > Python OpenCV - 動画のサムネイルを作る
Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【Pillow】ImageDraw.textによる文字の描画
ブログランキングに参加しています
画像ファイルを指定したファイルサイズまで自動で圧縮する
画像ファイルをメールに添付する場合など容量制限があるときに、手動でサイズ調整するのは面倒です。画像処理ライブラリOpenCVでjpen画像の縦横のピクセル数は元のまま、jpeg画像のファイルサイズ(容量)を指定したファイルサイズまで小さくします。OpenCVのcv2.imread()メソッドでjpeg画像を読み出し、cv2.imwrite()メソッドで画像を保存しますが、保存の際にcv2.IMWRITE_JPEG_QUALITYフラッグを用いてjpeg品質を指定します。保存したファイルの容量をチェックしあらかじめ指定したファイルサイズより大きければjpeg品質を下げてもう一度保存します。指定したファイルサイズより小さくなるまでこれを繰り返します。
使った関数・メソッド
- cv2.imread() : 画像ファイルの読み出し
- cv2.imwrite() : 画像の保存
- os.path.getsize() : ファイルサイズの取得
- cv2.IMWRITE_JPEG_QUALITY : imwriteのフラッグ。保存時のJpeg品質を指定する。引数のquality(品質)は0-100の範囲で指定。95がデフォルト。
関連記事
環境
準備
画像ファイルはフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名'books.jpg'で保存しました。画像サイズ1600x1071px、ファイルサイズは600kBです。
コード
画像の縦横のピクセル数は元のまま、jpeg品質を1つづつ小さくして画像を保存し画像のサイズを取得します。取得したサイズが狙いのサイズ(ここでは100kB)より小さくなるまで繰り返します。
import cv2 import os filename = 'books.jpg' target = 100 # 狙いのサイズ100kB img = cv2.imread(filename) size = os.path.getsize(filename) quality = 95 while size > target*1000: cv2.imwrite('compression.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), quality]) size = os.path.getsize('compression.jpg') quality -= 1
実行結果
画像サイズは1600x1071pxのままで、97kBまで圧縮された画像が保存されます。この時のjpeg品質は11です。
以下のサイトを参考にさせていただきました
note.nkmk.me > Pythonでファイル、ディレクトリ(フォルダ)のサイズを取得