【Python】動画再生アプリを作ってみる

動画再生アプリの解説ページアイキャッチ

このページでは Python で「動画を再生するアプリ」を作成する方法およびそのアプリのサンプルスクリプトについて解説していきます。

使用する外部ライブラリ・モジュールは Tkinter・OpenCV2・Pillow(PIL)になります。主に動画を扱うのが OpenCV2 ですので、残念ながら「音声なし」になります。

動作確認環境

このページで紹介するサンプルスクリプトは下記環境で動作確認を行っています

  • OS:macOS Catalina
  • Python:3.8
  • Tkinter:8.6
  • NumPy:1.18.2
  • OpenCV2:4.2.0
  • Pillow:7.1.1

作成するアプリ

今回作成するアプリは下のようなものになります。

動画再生アプリの出来上がりイメージ

アプリの画面

アプリの画面は下記のようなウィジェットから構成されます。

動画再生アプリの画面構成

アプリの動作

このアプリでは、ボタンを押したりマウス操作により下記を行うことができます。

  • 動画を読み込む
  • 動画を再生する
  • 動画を停止する
  • 動画をモノクロ化する
  • 動画をフリップする

動画を読み込む

「動画選択」ボタンをクリックすることで、動画ファイル(.MOV と .MP4)の選択を受け付け、選択された動画を読み込みます。

動画を再生する

動画を読み込むと画面左側のキャンバスに動画の最初のフレームおよび再生ボタンが表示されます。

この再生ボタンをクリックすると、動画を再生することができます。

動画再生ボタンの表示

この動画の再生について少し詳細を説明しておきます。

まず前提として、動画は簡単に言うと、複数枚の画像(フレームと言います)を連続して表示することで実現されます。

例えば下記の10枚のフレームから構成される動画があるとしましょう。

動画がフレームから構成される様子

動画を読み込むとこの先頭のフレームがキャンバスに描画されます(再生ボタンも)。

さらにキャンバスをクリックすれば、動画が再生されます。この再生は、フレームを一定間隔で次のフレームに切り替えることで実現しています。

フレームの切り替え

この切り替える間隔は、読み込んだ動画の FPS(1秒あたりの表示フレーム数)に基づいて計算していますので、大体読み込んだ動画を他のプレイヤーで再生した時と同じくらいのタイミングでフレームが切り替わると思います(若干ズレます)。

動画を停止する

動画再生中にキャンバスをクリックすると動画がその時点で停止します。

さらに動画が停止した状態でキャンバスをクリックすれば、停止した時点から動画の再生を再開することができます。

動画をモノクロ化する

「モノクロON/OFF」ボタンをクリックすれば、動画がモノクロ化されて表示されるようになります。

画像のモノクロ化

これは各フレームを描画する前に、そのフレームをモノクロ化することで実現しています。

動画がモノクロ化された状態で「モノクロON/OFF」ボタンを再度クリックすれば、動画がカラーに戻ります。

動画をフリップする

「フリップON/OFF」ボタンをクリックすれば、動画が左右反転されて表示されるようになります。

画像のフリップ

これは各フレームを描画する前に、そのフレームを左右反転することで実現しています。

動画が左右反転された状態で「フリップON/OFF」ボタンを再度クリックすれば、動画がさらに左右反転され、元に戻ります。

アプリのクラス設計

ではここからはアプリをどのように開発しているかについて解説していきたいと思います。

各クラスは「Model」と「View」と「Controller」の3つに分かれます。

Model」は動画や画像を扱うクラスで、「View」はアプリの見た目や描画を行うクラスです。「Controller」はユーザーからのイベント(ボタンクリック・マウス操作など)を受け付け、必要に応じて「Model」や「View」に処理の依頼を行うクラスになります。

Model クラス

Model クラスは下記の機能を提供します。

  • 動画オブジェクトの生成(create_video
  • フレーム進行(advance_frame
  • 画像オブジェクトの生成(create_image
  • 画像オブジェクトの取得(get_image
  • 動画のFPS取得(get_fps
  • 動画の巻き戻し(reverse_video
  • モノクロ設定(set_gray
  • フリップ設定(set_flip

動画オブジェクトの生成(create_video

Model クラスのオブジェクトは指定されたパスの動画から動画オブジェクトの生成を行います。

具体的には OpenCV2 の VideoCapture クラスのインスタンスの生成を行います。

動画オブジェクトの生成
self.video = cv2.VideoCapture(path)

フレーム進行(advance_frame

Model クラスのオブジェクトは動画オブジェクトからフレームの読み込みを行います。

フレームの読み込みと進行
# フレームの読み込み
ret, frame = self.video.read()

VideoCapture クラスの read メソッドは「次のフレーム」を NumPy 配列として読み込むメソッドです。

動画オブジェクト生成後に read メソッドを実行した場合、下記のようにフレームの読み取りとフレームの進行が行われていきます。

  • 1回目の read 実行:先頭フレームが読み込まれる
  • 2回目の read 実行:先頭フレームから2番目のフレームが読み込まれる
  • 3回目の read 実行:先頭フレームから3番目のフレームが読み込まれる
  • ・・・・
  • n回目の read 実行:先頭フレームからn番目のフレームが読み込まれる

こんな感じで read メソッドを実行することで、フレームの進行を実現しています。

また読み込んだフレームは次の「画像オブジェクト」の生成で利用します。

画像オブジェクトの生成(create_image

Model クラスのオブジェクトは読み込み済みのフレームに対して PIL 画像オブジェクトの生成および画像処理を行います。

具体的には下記の処理を行います。

  • モノクロ処理(モノクロ ON 時のみ)
  • フリップ処理(フリップ ON 時のみ)
  • PIL 画像オブジェクト生成
  • リサイズ

モノクロ処理は OpenCV2 を用いて下記により実行しています。frameVideoCapture クラスの read メソッドにより読み込まれた NumPy 配列のデータです。

モノクロ処理
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

またフリップ処理も OpenCV2 を用いて下記により実行しています。ちなみに第2引数を “0” にすれば上下反転することも可能です。

フリップ処理
frame = cv2.flip(frame, 1)

NumPy 配列 frame からの PIL 画像オブジェクト生成は下記により行っています。

PIL画像オブジェクトへの変換
# PIL イメージに変換
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
pil_image = Image.fromarray(rgb_frame)

この変換については下記ページで解説していますので、詳しく知りたい方は読んでみてください。

画像オブジェクト変換方法の解説ページアイキャッチ【Python】PIL ⇔ OpenCV2 ⇔ Tkinter 画像オブジェクトの相互変換

最後に指定されたサイズ(引数で指定)に合わせて画像のリサイズを行っています(指定されたサイズの矩形に内接に接するように、縦横同アスペクト比でリサイズ)。

主に画像を描画するキャンバスのサイズに合わせてリサイズすることを想定しています。

画像オブジェクトの取得(get_image

Model クラスのオブジェクトが持つ画像オブジェクトを取得する機能も提供しています。

PIL 画像オブジェクトを Tkinter 用のものに変換し、変換後の画像オブジェクトを返却します。

動画のFPS取得(get_fps

Model クラスのオブジェクトが持つ動画オブジェクトに対する動画の FPS を取得するための機能です。

FPSは VideoCapture クラスの set メソッドを下記のように実行することで取得することができます(video は VideoCapture クラスのインスタンス)。

FPSの取得
video.get(cv2.CAP_PROP_FPS)

動画の巻き戻し(reverse_video

Model クラスのオブジェクトが持つ動画オブジェクトに対する動画を先頭に巻き戻す機能です。

VideoCapture クラスの set メソッドを下記のように実行することで、動画を先頭に巻き戻すことができます(video は VideoCapture クラスのインスタンス)。

動画の巻き戻し
video.set(cv2.CAP_PROP_POS_FRAMES, 0)

モノクロ設定(set_gray

モノクロの ON/OFF を切り替えるための機能です。

この設定に応じて画像オブジェクトの生成(create_imageでモノクロ処理を行うかどうかが変わります。

フリップ設定(set_flip

フリップの ON/OFF を切り替えるための機能です。

この設定に応じて画像オブジェクトの生成(create_imageでフリップ処理を行うかどうかが変わります。

View クラス

View クラスは主に下記の機能を提供します。

  • ウィジェットの作成と配置(create_widgets
  • 画像の描画(draw_image
  • 再生ボタンの描画(draw_play_button
  • 再生ボタンの削除(delete_play_button
  • ファイル選択画面表示(select_open_file

ウィジェットの作成と配置(create_widgets

まず View クラスのオブジェクトはウィジェットの作成と配置を行います。

具体的には下図のようにウィジェットの配置を行なっています。

ウィジェットの配置

画像の描画

アプリ画面のキャンバスに対して画像の描画も行います。こちらは下記ページで解説していますのでこちらをご参照ください。

画像トリミングアプリの開発方法の解説ページアイキャッチ【Python】画像のトリミング(クロップ・切り取り)アプリを作ってみる【GUI】

再生ボタンの描画(draw_play_button

アプリ画面のキャンバスに対して、再生ボタンの描画も行っています。

動画再生ボタンの表示

単純に丸と三角を、サイズや配置を調整して再生ボタンっぽく見せているだけです。

丸も三角も Tkinter の Canvas クラスのメソッドを利用して簡単に描画することができます。

丸に関しては Canvas クラスの create_oval メソッドを、三角に関しては Canvas クラスの create_polygon メソッドを利用することで描画できます。

具体的なサイズや配置の調整をどのようにしているかはサンプルスクリプトの draw_play_button メソッドをご覧いただければと思います(かなりてきとうです…)。

再生ボタンの削除(delete_play_button

アプリ画面のキャンバス描画されている再生ボタンの削除を行います。

この再生ボタンの削除は Canvas クラスの delete メソッドにより、丸と三角を削除することで実現しています。

ファイル選択画面表示(select_open_file

またファイルを選択する際には、ファイル選択画面の表示も行います。

ファイル選択画面の表示については下記ページで解説していますので詳しく知りたい方はコチラを参照してください。

ファイル選択画面表示の解説ページアイキャッチPython でファイル選択画面を表示する

Controller クラス

Controller は下記を行うクラスです。

  • イベントの受け付け(set_events
  • 「動画選択」ボタンクリック時の処理(push_load_button
  • 「モノクロON/OFF」ボタンクリック時の処理(push_gray_button
  • 「フリップON/OFF」ボタンクリック時の処理(push_flip_button
  • マウスクリック時の処理(button_press
  • 定期的なフレーム進行処理(frame_timer
  • 定期的な画像描画処理(draw_timer

イベントの受け付け(set_events

Controller クラスの主な責務の1つがユーザーからのイベントの受け付けになります。ですので、View が設置したウィジェットに対してイベントの受け付け(bind)を行います。

イベント受け付けを詳しく知りたい方は是非下のページも読んでみてください。

tkinter解説ページのアイキャッtPython で Tkinter を使ってめちゃくちゃ簡単に GUI アプリを作る

「動画選択」ボタンクリック時の処理(push_load_button

「動画選択」ボタンクリックイベントが発生した際には Contoller クラスのオブジェクトは主に下記の処理を実行します。

  • View にファイル選択画面の表示を依頼(select_open_file
  • Model に動画オブジェクトの生成を依頼(create_video
  • 先頭フレームの表示
    advance_framecreate_imagereverse_videodraw_image
  • Model に再生ボタンの表示を依頼
    draw_play_buttondraw_play_button
  • フレーム進行用タイマー起動
  • 描画用タイマー起動

フレーム進行用タイマーは「定期的なフレーム進行処理(frame_timer)」を実行するためのもので、タイマーの時間は FPS(Model クラスの提供する get_fps メソッドで取得できた時間)から計算しています(単位は ms)。

フレーム進行用タイマー
# FPSに合わせてフレームを進める間隔を決定
fps = self.model.get_fps()
self.frame_timer = int(1 / fps * 1000 + 0.5)

# フレーム進行用のタイマースタート
self.master.after(self.frame_timer, self.frame)

描画用タイマーは「定期的な画像描画処理(draw_timer)」を実行するためのもので 50 ms に設定しています。

「モノクロON/OFF」ボタンクリック時の処理(push_gray_button

「モノクロON/OFF」ボタンクリックイベントが発生した際には Contoller クラスのオブジェクトは主に下記の処理を実行します。

  • Model にモノクロ ON/OFF 設定切り替え依頼(set_gray

「フリップON/OFF」ボタンクリック時の処理(push_flip_button

「フリップON/OFF」ボタンクリックイベントが発生した際には Contoller クラスのオブジェクトは主に下記の処理を実行します。

  • Model にフリップ ON/OFF 設定切り替え依頼(set_flip

マウス操作時の処理(button_press

キャンバス上でマウスがクリックされた時には Contoller クラスのオブジェクトは主に下記の処理を実行します。

  • 動画再生中の場合
    • 動画再生フラグを False にセット
    • Model に再生ボタンの表示を依頼(draw_play_button
  • 動画停止中の場合
    • 動画再生フラグを True にセット
    • Model に再生ボタンの削除を依頼(delete_play_button

定期的なフレーム進行処理(frame_timer

また Contoller クラスのオブジェクトは一定間隔毎(「動画選択」ボタンクリック時の処理(push_load_buttonで決定した間隔)に下記の処理を実行します。

  • タイマーの再起動
  •  動画再生中の場合のみ下記を実行
    • Model に動画のフレーム進行を依頼(advance_frame

 動画が最後まで進行された場合は下記の処理も行います。

  • Model に動画の巻き戻しを依頼(reverse_frame
  • Model に動画のフレーム進行を依頼(advance_frame

定期的な画像描画処理(draw_timer

また Contoller クラスのオブジェクトは一定間隔毎(「動画選択」ボタンクリック時の処理(push_load_buttonで決定した間隔)に下記の処理を実行します。

  • タイマーの再起動
  •  動画再生中の場合のみ下記を実行
    • Model に画像オブジェクト生成を依頼(create_image
    • View に画像描画を依頼(draw_image

ちなみに、定期処理を frame_timerdraw_timer の2つに分割しているのは、画像描画を行うための処理(create_imagedraw_image)が FPS の速度に間に合わないことがあるためです。

この場合、動画のフレーム切り替えが遅い、フレーム飛びするなどの問題が発生してしまいますので、 draw_timer は FPS からは切り離して時間設定(FPS よりも遅く画像描画を行うように設定)を行うようにしています。

MEMO

create_image の処理時間は print で標準出力しています

draw_timer の実行間隔はこの時間よりも余裕を持って設定してやればフレーム切り替えが遅い、フレーム飛びするなどの問題は防げるはずです

スポンサーリンク

アプリのサンプルスクリプト

ここまで説明してきたアプリのサンプルスクリプトは下記になります。

動画再生アプリ
import tkinter
import tkinter.filedialog
from PIL import Image, ImageTk
import cv2
import time


class Model():

	def __init__(self):

		# 動画オブジェクト参照用
		self.video = None

		# 画像処理の設定
		self.gray = False
		self.flip= False

		# 読み込んだフレーム
		self.frames = None

		# PIL画像オブジェクト参照用
		self.image = None

		# Tkinter画像オブジェクト参照用
		self.image_tk = None


	def create_video(self, path):
		'動画オブジェクトの生成を行う'

		# pathの動画から動画オブジェクト生成
		self.video = cv2.VideoCapture(path)

	def advance_frame(self):
		'フレームを読み込んで1フレーム進める'

		if not self.video:
			return

		# フレームの読み込み
		ret, self.frame = self.video.read()
		
		return ret

	def reverse_video(self):
		'動画を先頭に戻す'

		self.video.set(cv2.CAP_PROP_POS_FRAMES, 0)

	def create_image(self, size):
		'フレームの画像を作成'

		t1 = time.time()

		# フレームを読み込み
		frame = self.frame
		if frame is None:
			print("None")

		# 設定に応じて画像処理
		if self.gray:
			frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
		if self.flip:
			frame = cv2.flip(frame, 1)

		# PIL イメージに変換
		rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
		pil_image = Image.fromarray(rgb_frame)
		
		# 指定サイズに合わせて画像をリサイズ

		# 拡大率を計算
		ratio_x = size[0] / pil_image.width
		ratio_y = size[1] / pil_image.height

		if ratio_x < ratio_y:
			ratio = ratio_x
		else:
			ratio = ratio_y

		# リサイズ
		self.image = pil_image.resize(
			(
				int(ratio * pil_image.width),
				int(ratio * pil_image.height)
			)
		)
		t2 = time.time()

		print(f"経過時間:{t2-t1}")

	def get_image(self):
		'Tkinter画像オブジェクトを取得する'

		if self.image is not None:
			# Tkinter画像オブジェクトに変換
			self.image_tk = ImageTk.PhotoImage(self.image)
		return self.image_tk

	def get_fps(self):
		'動画のFPSを取得する'

		if self.video is None:
			return None

		return self.video.get(cv2.CAP_PROP_FPS)

	def set_gray(self):
		self.gray = not self.gray

	def set_flip(self):
		self.flip = not self.flip

class View():

	def __init__(self, app, model):

		self.master = app
		self.model = model

		# アプリ内のウィジェットを作成
		self.create_widgets()

	def create_widgets(self):
		'アプリ内にウィジェットを作成・配置する'

		# キャンバスのサイズ
		canvas_width = 500
		canvas_height = 300

		# キャンバスとボタンを配置するフレームの作成と配置
		self.main_frame = tkinter.Frame(
			self.master
		)
		self.main_frame.pack()

		# キャンバスを配置するフレームの作成と配置
		self.canvas_frame = tkinter.Frame(
			self.main_frame
		)
		self.canvas_frame.grid(column=1, row=1)

		# ユーザ操作用フレームの作成と配置
		self.operation_frame = tkinter.Frame(
			self.main_frame
		)
		self.operation_frame.grid(column=2, row=1)


		# キャンバスの作成と配置
		self.canvas = tkinter.Canvas(
			self.canvas_frame,
			width=canvas_width,
			height=canvas_height,
			bg="#EEEEEE",
		)
		self.canvas.pack()

		# ファイル読み込みボタンの作成と配置
		self.load_button = tkinter.Button(
			self.operation_frame,
			text="動画選択"
		)
		self.load_button.pack()

		# グレーON/OFFボタンの作成と配置
		self.gray_button = tkinter.Button(
			self.operation_frame,
			text="モノクロON/OFF"
		)
		self.gray_button.pack()

		# フリップ/OFFボタンの作成と配置
		self.flip_button = tkinter.Button(
			self.operation_frame,
			text="フリップON/OFF"
		)
		self.flip_button.pack()


	def draw_image(self):
		'画像をキャンバスに描画'

		image = self.model.get_image()

		if image is not None:
			# キャンバス上の画像の左上座標を決定
			sx = (self.canvas.winfo_width() - image.width()) // 2
			sy = (self.canvas.winfo_height() - image.height()) // 2

			# キャンバスに描画済みの画像を削除
			objs = self.canvas.find_withtag("image")
			for obj in objs:
				self.canvas.delete(obj)

			# 画像をキャンバスの真ん中に描画
			self.canvas.create_image(
				sx, sy,
				image=image,
				anchor=tkinter.NW,
				tag="image"
			)

	def select_open_file(self, file_types):
		'オープンするファイル選択画面を表示'

		# ファイル選択ダイアログを表示
		file_path = tkinter.filedialog.askopenfilename(
			initialdir=".",
			filetypes=file_types
		)
		return file_path

	def draw_play_button(self):
		'再生ボタンを描画'

		# キャンバスのサイズ取得
		width = self.canvas.winfo_width()
		height = self.canvas.winfo_height()

		# 円の直径を決定
		if width > height:
			diameter = height
		else:
			diameter = width

		# 端からの距離を計算
		distance = diameter / 10

		# 円の線の太さを計算
		thickness = distance

		# 円の描画位置を決定
		sx = (width - diameter) // 2 + distance
		sy = (height - diameter) // 2 + distance
		ex = width - (width - diameter) // 2 - distance
		ey = height - (height - diameter) // 2 - distance

		# 丸を描画
		self.canvas.create_oval(
			sx, sy,
			ex, ey,
			outline="white",
			width=thickness,
			tag="oval"
		)

		# 頂点座標を計算
		x1 = sx + distance * 3
		y1 = sy + distance * 2
		x2 = sx + distance * 3
		y2 = ey - distance * 2
		x3 = ex - distance * 2
		y3 = height // 2

		# 三角を描画
		self.canvas.create_polygon(
			x1, y1,
			x2, y2,
			x3, y3,
			fill="white",
			tag="triangle"
		)

	def delete_play_button(self):
		self.canvas.delete("oval")
		self.canvas.delete("triangle")

class Controller():

	def __init__(self, app, model, view):
		self.master = app
		self.model = model
		self.view = view


		# 動画再生中かどうかの管理
		self.playing = False

		# フレーム進行する間隔
		self.frame_timer = 0

		# 描画する間隔
		self.draw_timer = 50

		self.set_events()

	def set_events(self):
		'受け付けるイベントを設定する'

		# キャンバス上のマウス押し下げ開始イベント受付
		self.view.canvas.bind(
			"",
			self.button_press
		)

		# 動画選択ボタン押し下げイベント受付
		self.view.load_button['command'] = self.push_load_button

		# モノクロON/OFFボタン押し下げイベント受付
		self.view.gray_button['command'] = self.push_gray_button

		# フリップON/OFFボタン押し下げイベント受付
		self.view.flip_button['command'] = self.push_flip_button

	def draw(self):
		'一定間隔で画像等を描画'

		# 再度タイマー設定
		self.master.after(self.draw_timer, self.draw)

		# 動画再生中の場合
		if self.playing:
			# フレームの画像を作成
			self.model.create_image(
				(
					self.view.canvas.winfo_width(),
					self.view.canvas.winfo_height()
				)
			)

			# 動画1フレーム分をキャンバスに描画
			self.view.draw_image()

	def frame(self):
		'一定間隔でフレームを進める'

		# 再度タイマー設定
		self.master.after(self.frame_timer, self.frame)

		# 動画再生中の場合
		if self.playing:
			# 動画を1フレーム進める
			ret = self.model.advance_frame()

			# フレームが進められない場合
			if not ret:
				# フレームを最初に戻す
				self.model.reverse_video()
				self.model.advance_frame()
			
		
	def push_load_button(self):
		'動画選択ボタンが押された時の処理'

		file_types = [
			("MOVファイル", "*.mov"),
			("MP4ファイル", "*.mp4"),
		]

		# ファイル選択画面表示
		file_path = self.view.select_open_file(file_types)

		if len(file_path) != 0:

			# 動画オブジェクト生成
			self.model.create_video(file_path)

			# 最初のフレームを表示
			self.model.advance_frame()
			self.model.create_image(
				(
					self.view.canvas.winfo_width(),
					self.view.canvas.winfo_height()
				)
			)
			self.model.reverse_video()
			self.view.draw_image()

			# 再生ボタンの表示
			self.view.delete_play_button()
			self.view.draw_play_button()

			# FPSに合わせてフレームを進める間隔を決定
			fps = self.model.get_fps()
			self.frame_timer = int(1 / fps * 1000 + 0.5)

			# フレーム進行用のタイマースタート
			self.master.after(self.frame_timer, self.frame)

			# 画像の描画用のタイマーセット
			self.master.after(self.draw_timer, self.draw)

	def button_press(self, event):
		'マウスボタン押された時の処理'

		# 動画の再生/停止を切り替える
		if not self.playing:
			self.playing = True

			# 再生ボタンの削除
			self.view.delete_play_button()
		else:
			self.playing = False
			
			# 再生ボタンの描画
			self.view.draw_play_button()

	def push_gray_button(self):
		self.model.set_gray()

	def push_flip_button(self):
		self.model.set_flip()



app = tkinter.Tk()

app.title("動画再生アプリ")

model = Model()
view = View(app, model)
controller = Controller(app, model, view)

app.mainloop()

実行すると下記のような画面が表示されます。

アプリ起動画面

「動画選択」ボタンを押せばファイル選択画面が表示されるので、動画ファイル(.MOV or .MP4)を選んでください。選んだ動画の先頭フレームと動画再生ボタンがキャンバスに描画されます。

最初のフレームと再生ボタンの表示

キャンバス(動画再生ボタン)をクリックすると、動画の再生が始まります。

「モノクロON/OFF」ボタンをクリックすると画像のカラー・モノクロが切り替わります。

動画がモノクロ化される様子

また「フリップON/OFF」ボタンをクリックすると画像の左右が反転します。

画像がフリップされる様子

またキャンバスをクリックすると動画の再生が停止し、動画再生ボタンが表示されます。

まとめ

このページでは Python で動画を再生するアプリ開発の説明を行いました。

Python での動画再生だけでなく、GUI アプリの作り方やタイマーを利用した画像のリアルタイム描画処理についても学べる良いテーマだと思います!

今回は動画に対してモノクロ処理・フリップ処理を行いましたが、OpenCV2 を利用して顔認識などを行いながら動画再生を行うようなことも可能です(動画の顔部分を色をつけて表示するなど)。

様々な発展のさせ方があると思いますので、是非色々カスタマイズを行い、Python や動画・画像・認識処理についての学習に役立ててください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です