Pythonでいろいろやってみる

Pythonを使った画像処理や機械学習などの簡単なプログラムを載せています。

動画を明るく鮮やかにする

 動画を明るく鮮やかにします。画像処理ライブラリOpenCVで動画ファイルを読み出し、フレーム毎の画像をBGR色空間からHSV色空間に変換します。画像のS(彩度)、V(明るさ)に対してcv2.LUTでガンマカーブ(γ=1.5)のルックアップテーブルを適用し、その画像をつなぎ合わせて明るく鮮やかな動画にします。

関連記事

アジサイの写真を明るく鮮やかにする

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
  • OpenCV 4.0.1
準備

動画ファイルは動画ACの「山の草原で体をひねる運動をする女性」をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’woman.mp4'で保存しました(動画のサイズは320x180)。このブログにはmovファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。

f:id:T_A_T:20220126210934g:plain
woman.mp4(gifファイルに変換したもの)

コード

 cv2.VideoCaptureで動画を取り込み、各フレームをcv2.cvtColorでBGRからHSVに色空間を変換します。HSV画像をチャンネル別に分離しS(彩度)、V(明度)に対してcv2.LUTでγ=1.5のガンマカーブのルックアップテーブルを適用、ガンマ補正で彩度と明度を強調します。

from PIL import Image
import cv2
import numpy as np

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 動画ファイルのキャプチャー
cap = cv2.VideoCapture('woman.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('vivid.mp4', fourcc, fps, (int(width), int(height))) 

# 変換用ルックアップテーブルの生成
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

# 動画を1コマずつ取り込んで処理
while(cap.isOpened()): 
    ret, frame = cap.read() # キャプチャー画像の取り込み
    
    if ret==True: # キャプチャー画像がある場合
                
        # 色空間を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) 
                
        # VideoWriterにフレームを追加
        out.write(bgr)

        # gifファイル作成用イメージリストにフレームを追加
        images.append(Image.fromarray(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)))

    else: # キャプチャー画像がない場合はループ終了 
        break
        
cap.release() # 再生画像をクローズ   
out.release() # 出力動画ファイルをクローズ

# gif動画保存
images[0].save('vivid.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=1000/fps, loop=0)      
実行結果

明るく鮮やかになった動画が保存されます。
f:id:T_A_T:20220126211417g:plain
こちらが変換前。
f:id:T_A_T:20220126210934g:plain

以下のサイトを参考にさせていただきました

Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【OpenCV】LUTによる画像変換

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

フォルダ内の画像からスライドショーを作る(スワイプ切り替え)

 指定したフォルダ内の画像を読み出しスライドショーを作ります。画像はサイズがまちまちなのでスライドショーのサイズに対して横幅が大きい場合は左右を、高さが大きい場合は上下をカットして、スライドショーのサイズに自動で変換します。画像と画像の切り替えは左から次の画像が少しずつ現れるいわゆるスワイプ切り替えします。
 画像処理ライブラリPillowのcropで画像のサイズ合わせを、compositeでマスク画像を使って次の画像を左から少しずつ表示させます。   

関連記事

フォルダ内の画像からスライドショーを作る(フェード切り替え)
フォルダ内の画像からスライドショーを作る(ブラックアウト、ホワイトアウト切り替え)

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
準備

 以下の画像ファイルをフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'photos'を作成しその中に保存しました。
f:id:T_A_T:20220124191718j:plain
asama.jpg

f:id:T_A_T:20220124191740j:plain
autumn.jpg

f:id:T_A_T:20220124191819j:plain
cat.jpg

f:id:T_A_T:20220124191906j:plain
girl.jpg

f:id:T_A_T:20220124191925j:plain
hongkong.jpg

f:id:T_A_T:20220124191937j:plain
xmas.jpg

コード

 photosフォルダに含まれるファイルのリストを作り、画像を読み出してサイズを調整しtempフォルダに格納します。tempフォルダから画像を読み出し20コマgifファイルに追加、続く20コマで黒地に白い四角を描いたマスク画像を用意し、その白い領域を変えながら画像と次の画像を合成し次の画像が左から現れるように見せます(スワイプ)。最後の画像から最初の画像へのスワイプが必要なのでファイルのリストの最後に一番最初の画像をもう一度追加しています。

import os
from PIL import Image, ImageDraw

# 画像フォルダのパス
dir_path = 'photos/' 
# フォルダ内のファイルをリストに
files = os.listdir(dir_path)
# 1番目のファイルをリストの最後に追加
files.append(files[0]) 

# スライドショーの幅、高設定
s_width, s_height = 500, 250
# スライドショーのアスペクト比(高さ/幅)
s_aspect = s_height/s_width

# gifファイル作成用イメージリスト
images =[] 

# サイズ調整した画像の一時保存用リスト
temp = []

# 画像をサイズ調整しリストに追加
for i in range(len(files)):
    # 画像の読み出し
    im = Image.open(dir_path + files[i])
    # 画像幅、高さの取得、アスペクト比(高さ/幅)の算出
    width = im.width
    height = im.height
    aspect = height/width
    # 画像のアスペクト比がスライドショーと同じ場合そのままスライドショーサイズにリサイズ
    if aspect == s_aspect:
        resize = im.resize((s_width, s_height))            
    # 画像のアスペクト比がスライドショーより大きい場合上下をカットしスライドショーサイズにリサイズ
    if aspect > s_aspect:
        crop_size = int((height-s_aspect*width)/2)
        crop = im.crop((0, crop_size, width, height-crop_size))
        resize = crop.resize((s_width, s_height))    
    # 画像のアスペクト比がスライドショーより小さい場合左右をカットしスライドショーサイズにリサイズ
    if aspect < s_aspect:
        crop_size = int((width-height/s_aspect)/2)
        crop = im.crop((crop_size, 0, width-crop_size, height))
        resize = crop.resize((s_width, s_height))
    # リサイズした画像をリストに追加    
    temp.append(resize)

# リストから画像を読みだしスライドショーに
for i in range(len(files)-1):
    # 画像の読み出し
    im = temp[i]
    # 次の画像の読み出し
    im2 = temp[i+1]  
    # gifファイルに画像を20コマ追加    
    for j in range(20):
        images.append(im)      
    # 次の画像とスワイプして画像をゆっくり切り替える    
    for j in range(30):
        mask = Image.new('1', (s_width, s_height))
        draw = ImageDraw.Draw(mask)
        draw.rectangle([(int(j/29*s_width), 0), (s_width, s_height)], 
                fill='white', outline='white', width=1)
        blend = Image.composite(im, im2, mask)
        images.append(blend)
        
# gif動画保存
images[0].save('slideshow_swipe.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=50, loop=0)      

実行結果

スライドショーがgifアニメーションになって保存されます。次の画像が左から徐々に現れて切り替わります(スワイプ)。
f:id:T_A_T:20220124203928g:plain

以下のサイトを参考にさせていただきました

note.nkmk.me>>Python, OpenCV, Pillow(PIL)で画像サイズ(幅、高さ)を取得
Pythonの文法メモ > 【Pillow】画像の縮小拡大(resize)、切り抜き(crop)
Pythonの文法メモ > 【Pillow】画像の新規作成(Image.new)
Pythonの文法メモ > 【Pillow】マスクを使った画像の合成
Pythonの文法メモ > 【Pillow】ImageDrawモジュールによる直線、四角、円、多角形描画

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

フォルダ内の画像からスライドショーを作る(ブラックアウト、ホワイトアウト切り替え)

 指定したフォルダ内の画像を読み出しスライドショーを作ります。画像はサイズがまちまちなのでスライドショーのサイズに対して横幅が大きい場合は左右を、高さが大きい場合は上下をカットして、スライドショーのサイズに自動で変換します。画像と画像の切り替えは前の画像が少しずつ薄れ黒画像(白画像)になってから次の画像が少しずつ濃くなるように(いわゆるブラックアウト、ホワイトアウト)画像を黒画像(白画像)とアルファブレンドしアルファ値を変化させています。
 画像処理ライブラリPillowのcropで画像のサイズ合わせを、blendで画像と黒画像(白画像)のアルファブレンドを行っています。   

関連記事

フォルダ内の画像からスライドショーを作る(フェード切り替え)

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
準備

 以下の画像ファイルをフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'photos'を作成しその中に保存しました。
f:id:T_A_T:20220124191718j:plain
asama.jpg

f:id:T_A_T:20220124191740j:plain
autumn.jpg

f:id:T_A_T:20220124191819j:plain
cat.jpg

f:id:T_A_T:20220124191906j:plain
girl.jpg

f:id:T_A_T:20220124191925j:plain
hongkong.jpg

f:id:T_A_T:20220124191937j:plain
xmas.jpg

コード

 photosフォルダに含まれるファイルのリストを作り、画像を読み出してサイズを調整しtempフォルダに格納します。tempフォルダから画像を読み出し20コマgifファイルに追加、続く10コマでアルファ値を変えながら画像を黒画像とアルファブレンド、続く10コマでアルファ値を変えながら黒画像と次の画像をアルファブレンドし一度ブラックアウトしてから次の画像に移るように見せます。最後の画像から最初の画像へのブラックアウトが必要なのでファイルのリストの最後に一番最初の画像をもう一度追加しています。

import os
from PIL import Image

# 画像フォルダのパス
dir_path = 'photos/' 
# フォルダ内のファイルをリストに
files = os.listdir(dir_path)
# 1番目のファイルをリストの最後に追加
files.append(files[0]) 

# スライドショーの幅、高設定
s_width, s_height = 500, 250
# スライドショーのアスペクト比(高さ/幅)
s_aspect = s_height/s_width

# ブラックアウト用黒画像作成
black = Image.new('RGB', (s_width, s_height), (0, 0, 0))

# gifファイル作成用イメージリスト
images =[] 

# サイズ調整した画像の一時保存用リスト
temp = []

# 画像をサイズ調整しリストに追加
for i in range(len(files)):
    # 画像の読み出し
    im = Image.open(dir_path + files[i])
    # 画像幅、高さの取得、アスペクト比(高さ/幅)の算出
    width = im.width
    height = im.height
    aspect = height/width
    # 画像のアスペクト比がスライドショーと同じ場合そのままスライドショーサイズにリサイズ
    if aspect == s_aspect:
        resize = im.resize((s_width, s_height))            
    # 画像のアスペクト比がスライドショーより大きい場合上下をカットしスライドショーサイズにリサイズ
    if aspect > s_aspect:
        crop_size = int((height-s_aspect*width)/2)
        crop = im.crop((0, crop_size, width, height-crop_size))
        resize = crop.resize((s_width, s_height))    
    # 画像のアスペクト比がスライドショーより小さい場合左右をカットしスライドショーサイズにリサイズ
    if aspect < s_aspect:
        crop_size = int((width-height/s_aspect)/2)
        crop = im.crop((crop_size, 0, width-crop_size, height))
        resize = crop.resize((s_width, s_height))
    # リサイズした画像をリストに追加    
    temp.append(resize)

# リストから画像を読みだしスライドショーに
for i in range(len(files)-1):
    # 画像の読み出し
    im = temp[i]
    # 次の画像の読み出し
    im2 = temp[i+1]  
    # gifファイルに画像を20コマ追加    
    for j in range(20):
        images.append(im)      
    # 画像と黒画像をブレンドして画像をゆっくり消す    
    for j in range(10):
        blend = Image.blend(im, black, j/9)
        images.append(blend)
    # 黒画像と次の画像をブレンドして画像をゆっくり出現させる    
    for j in range(10):
        blend = Image.blend(black, im2, j/9)
        images.append(blend)

# gif動画保存
images[0].save('slideshow_black.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=50, loop=0)   
実行結果

スライドショーがgifアニメーションになって保存されます。画像は黒画像を挟んで徐々に切り替わります(ブラックアウト)。
f:id:T_A_T:20220124200551g:plain


コード

 画像切り替え時の画像を黒から白に変えてホワイトアウト切り替えにします。

import os
from PIL import Image

# 画像フォルダのパス
dir_path = 'photos/' 
# フォルダ内のファイルをリストに
files = os.listdir(dir_path)
# 1番目のファイルをリストの最後に追加
files.append(files[0]) 

# スライドショーの幅、高設定
s_width, s_height = 500, 250
# スライドショーのアスペクト比(高さ/幅)
s_aspect = s_height/s_width

# ホワイトアウト用白画像作成
white = Image.new('RGB', (s_width, s_height), (255, 255, 255))

# gifファイル作成用イメージリスト
images =[] 

# サイズ調整した画像の一時保存用リスト
temp = []

# 画像をサイズ調整しリストに追加
for i in range(len(files)):
    # 画像の読み出し
    im = Image.open(dir_path + files[i])
    # 画像幅、高さの取得、アスペクト比(高さ/幅)の算出
    width = im.width
    height = im.height
    aspect = height/width
    # 画像のアスペクト比がスライドショーと同じ場合そのままスライドショーサイズにリサイズ
    if aspect == s_aspect:
        resize = im.resize((s_width, s_height))            
    # 画像のアスペクト比がスライドショーより大きい場合上下をカットしスライドショーサイズにリサイズ
    if aspect > s_aspect:
        crop_size = int((height-s_aspect*width)/2)
        crop = im.crop((0, crop_size, width, height-crop_size))
        resize = crop.resize((s_width, s_height))    
    # 画像のアスペクト比がスライドショーより小さい場合左右をカットしスライドショーサイズにリサイズ
    if aspect < s_aspect:
        crop_size = int((width-height/s_aspect)/2)
        crop = im.crop((crop_size, 0, width-crop_size, height))
        resize = crop.resize((s_width, s_height))
    # リサイズした画像をリストに追加    
    temp.append(resize)

# リストから画像を読みだしスライドショーに
for i in range(len(files)-1):
    # 画像の読み出し
    im = temp[i]
    # 次の画像の読み出し
    im2 = temp[i+1]  
    # gifファイルに画像を20コマ追加    
    for j in range(20):
        images.append(im)      
    # 画像と白画像をブレンドして画像をゆっくり消す    
    for j in range(10):
        blend = Image.blend(im, white, j/9)
        images.append(blend)
    # 白画像と次の画像をブレンドして画像をゆっくり出現させる    
    for j in range(10):
        blend = Image.blend(white, im2, j/9)
        images.append(blend)

# gif動画保存
images[0].save('slideshow_white.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=50, loop=0)   
実行結果

スライドショーがgifアニメーションになって保存されます。画像は白画像を挟んで徐々に切り替わります(ホワイトアウト)。
f:id:T_A_T:20220124200900g:plain

以下のサイトを参考にさせていただきました

note.nkmk.me>>Python, OpenCV, Pillow(PIL)で画像サイズ(幅、高さ)を取得
Pythonの文法メモ > 【Pillow】画像のアルファブレンド(blend、alpha_composit)
Pythonの文法メモ > 【Pillow】画像の縮小拡大(resize)、切り抜き(crop)
Pythonの文法メモ > 【Pillow】画像の新規作成(Image.new)

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

フォルダ内の画像からスライドショーを作る(フェード切り替え)

 指定したフォルダ内の画像を読み出しスライドショーを作ります。画像はサイズがまちまちなのでスライドショーのサイズに対して横幅が大きい場合は左右を、高さが大きい場合は上下をカットして、スライドショーのサイズに自動で変換します。画像と画像の切り替えは前の画像が少しずつ薄れ次の画像が少しずつ濃くなるように(いわゆるフェードもしくはディゾルブ)前後の画像をアルファブレンドしアルファ値を変化させています。
 画像処理ライブラリPillowのcropで画像のサイズ合わせを、blendで前後の画像のアルファブレンドを行っています。   

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
準備

 以下の画像ファイルをフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'photos'を作成しその中に保存しました。
f:id:T_A_T:20220124191718j:plain
asama.jpg

f:id:T_A_T:20220124191740j:plain
autumn.jpg

f:id:T_A_T:20220124191819j:plain
cat.jpg

f:id:T_A_T:20220124191906j:plain
girl.jpg

f:id:T_A_T:20220124191925j:plain
hongkong.jpg

f:id:T_A_T:20220124191937j:plain
xmas.jpg

コード

 photosフォルダに含まれるファイルのリストを作り、画像を読み出してサイズを調整しtempフォルダに格納します。tempフォルダから画像を読み出し20コマgifファイルに追加、続く20コマで前後の画像をアルファブレンドし徐々に次の画像に移るように見せます。最後の画像から最初の画像へのディゾルブが必要なのでファイルのリストの最後に一番最初の画像をもう一度追加しています。

import os
from PIL import Image

# 画像フォルダのパス
dir_path = 'photos/' 
# フォルダ内のファイルをリストに
files = os.listdir(dir_path)
# 1番目のファイルをリストの最後に追加
files.append(files[0]) 

# スライドショーの幅、高設定
s_width, s_height = 500, 250
# スライドショーのアスペクト比(高さ/幅)
s_aspect = s_height/s_width

# gifファイル作成用イメージリスト
images =[] 

# サイズ調整した画像の一時保存用リスト
temp = []

# 画像をサイズ調整しリストに追加
for i in range(len(files)):
    # 画像の読み出し
    im = Image.open(dir_path + files[i])
    # 画像幅、高さの取得、アスペクト比(高さ/幅)の算出
    width = im.width
    height = im.height
    aspect = height/width
    # 画像のアスペクト比がスライドショーと同じ場合そのままスライドショーサイズにリサイズ
    if aspect == s_aspect:
        resize = im.resize((s_width, s_height))            
    # 画像のアスペクト比がスライドショーより大きい場合上下をカットしスライドショーサイズにリサイズ
    if aspect > s_aspect:
        crop_size = int((height-s_aspect*width)/2)
        crop = im.crop((0, crop_size, width, height-crop_size))
        resize = crop.resize((s_width, s_height))    
    # 画像のアスペクト比がスライドショーより小さい場合左右をカットしスライドショーサイズにリサイズ
    if aspect < s_aspect:
        crop_size = int((width-height/s_aspect)/2)
        crop = im.crop((crop_size, 0, width-crop_size, height))
        resize = crop.resize((s_width, s_height))
    # リサイズした画像をリストに追加    
    temp.append(resize)

# リストから画像を読みだしスライドショーに
for i in range(len(files)-1):
    # 画像の読み出し
    im = temp[i]
    # 次の画像の読み出し
    im2 = temp[i+1]  
    # gifファイルに画像を20コマ追加    
    for j in range(20):
        images.append(im)      
    # 次の画像とブレンドして画像をゆっくり切り替える    
    for j in range(20):
        blend = Image.blend(im, im2, j/19)
        images.append(blend)
        
# gif動画保存
images[0].save('slideshow.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=50, loop=0)  

実行結果

スライドショーがgifアニメーションになって保存されます。画像は徐々に切り替わります(フェードもしくはディゾルブ)。
f:id:T_A_T:20220124183504g:plain

以下のサイトを参考にさせていただきました

note.nkmk.me>>Python, OpenCV, Pillow(PIL)で画像サイズ(幅、高さ)を取得
Pythonの文法メモ > 【Pillow】画像のアルファブレンド(blend、alpha_composit)
Pythonの文法メモ > 【Pillow】画像の縮小拡大(resize)、切り抜き(crop)

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

動画をモノクロ映画っぽくする

 動画をモノクロ映画っぽくします。カラーの動画ファイルを読み出し各フレームをグレースケール変換して動画として保存します。画像処理ライブラリOpenCVで動画ファイルを読み出し、フレーム毎の画像をcv2.cvtColorでグレースケール変換しその画像をつなぎ合わせて動画にします。さらにコントラストを強調することでよりモノクロ映画っぽくします。

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
  • OpenCV 4.0.1
準備

 動画ファイルはMixkitの "Annoyed man yelling at his wife"をダウンロードし320x180にリサイズしたうえでjupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’yelling.mp4'で保存しました。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。

f:id:T_A_T:20220123183613g:plain
"yelling.mp4(アニメーションgifに変換したもの)"

コード

cv2.cvtColorにより各フレームをグレースケール変換しmp4動画として保存します。

from PIL import Image
import cv2

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 動画ファイルのキャプチャー
cap = cv2.VideoCapture('yelling.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('monochrome.mp4', fourcc, fps, (int(width), int(height))) 

# 動画を1コマずつ取り込んで処理
while(cap.isOpened()): 
    ret, frame = cap.read() # キャプチャー画像の取り込み
    
    if ret==True: # キャプチャー画像がある場合
                
        # グレースケール変換
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        # BGR変換(動画ファイルとチャンネル数を合わせるため)
        bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

        # VideoWriterにフレームを追加
        out.write(bgr)

        # gifファイル作成用イメージリストにフレームを追加
        images.append(Image.fromarray(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)))

    else: # キャプチャー画像がない場合はループ終了 
        break
        
cap.release() # 再生画像をクローズ   
out.release() # 出力動画ファイルをクローズ

# gif動画保存
images[0].save('monochrome.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=1000/fps, loop=0)  
実行結果

モノクロ変換された動画が保存されます。
f:id:T_A_T:20220123184209g:plain


コード

よりモノクロ映画っぽくするために画像のコントラストを強調します。cv2.equalizeHistでヒストグラム平坦化しコントラストを強調してからグレースケール変換します。

from PIL import Image
import cv2

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 動画ファイルのキャプチャー
cap = cv2.VideoCapture('yelling.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('monochrome_eq.mp4', fourcc, fps, (int(width), int(height))) 

# 動画を1コマずつ取り込んで処理
while(cap.isOpened()): 
    ret, frame = cap.read() # キャプチャー画像の取り込み
    
    if ret==True: # キャプチャー画像がある場合
                
        # 色空間をBGR->HSVに変換
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)         
        
        # equalizeHistによるヒストグラム平坦化
        hsv[:, :, 2] = cv2.equalizeHist(hsv[:, :, 2])

        # HSV->BGR変換
        bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) 
        
        # グレースケール変換
        gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)
        
        # BGR変換(動画ファイルとチャンネル数を合わせるため)
        bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
        
        # VideoWriterにフレームを追加
        out.write(bgr)

        # gifファイル作成用イメージリストにフレームを追加
        images.append(Image.fromarray(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)))

    else: # キャプチャー画像がない場合はループ終了 
        break
        
cap.release() # 再生画像をクローズ   
out.release() # 出力動画ファイルをクローズ

# gif動画保存
images[0].save('monochrome_eq.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=1000/fps, loop=0)   
実行結果

コントラストが強調されより古い映画っぽくなります。
f:id:T_A_T:20220123184253g:plain

以下のサイトを参考にさせていただきました

Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【OpenCV】ヒストグラム平坦化による画像コントラストの向上

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

UFO動画を作る

 夜景の動画の空にUFOを追加します。動画ファイルを読み出して移動する楕円形を描画し再び動画として保存します。画像処理ライブラリOpenCVで動画ファイルを読み出し、フレーム毎の画像にcv2.ellipseで楕円形を描画し、その画像をつなぎ合わせてUFO動画にします。途中で楕円の動きを変化させUFOっぽくします。

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
  • OpenCV 4.0.1
準備

 動画ファイルはMixkitの "Fireworks in the beach"をダウンロードし320x180にリサイズしたうえでjupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’firework.mp4'で保存しました。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。

f:id:T_A_T:20220122143904g:plain
firework.mp4(アニメーションgifに変換したもの)

コード

①最終フレームから100フレーム前まで普通に再生
②最終フレームから100フレーム前に来たところで25フレーム逆再生し25フレーム順再生。これを3回繰り返す
③最終フレームまで普通に再生
として行ったり来たりする動画にしてmp4ファイルとgifアニメーションで保存します。なお保存する動画のフレームサイズは元の640x360を縦横半分の320x180にしています。

from PIL import Image
import cv2

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 動画ファイルのキャプチャー
cap = cv2.VideoCapture('firework.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('ufo.mp4', fourcc, fps, (int(width), int(height))) 

# 楕円の初期値
x = 180  # x座標
y = -10  # y座標
dx = 0.6  # x座標の変化量
dy = 0.5  # y座標の変化量
a = 3  # 楕円のx方向半径 
b = 0.6  # 楕円のy方向半径
mag = 1  # 楕円の拡大率
dmag = 0.008  # 楕円の拡大率の変化量

# 動画を1コマずつ取り込んで処理
while(cap.isOpened()): 
    ret, frame = cap.read() # キャプチャー画像の取り込み
    
    if ret==True: # キャプチャー画像がある場合
        
        # 画像に楕円を描画
        cv2.ellipse(frame, (int(x), int(y)), (int(a*mag), int(b*mag)), 
                    0, 0, 360 ,(55, 255, 255), -1, cv2.LINE_AA)
        
        # VideoWriterにフレームを追加
        out.write(frame)

        # gifファイル作成用イメージリストにフレームを追加
        images.append(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
        
        # 現在時間を取得
        time = cap.get(cv2.CAP_PROP_POS_MSEC)

        # 5000msec以降は楕円の移動方向・距離と拡大率を変更
        if time > 5000:
            dx = 4
            dy = -0.3
            dmag = -0.015
            
        # 楕円のx,y座標の変更、拡大率の変更
        x += dx
        y += dy
        mag += dmag
        
    else: # キャプチャー画像がない場合はループ終了 
        break
        
cap.release() # 再生画像をクローズ   
out.release() # 出力動画ファイルをクローズ

# gif動画保存
images[0].save('ufo.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=1000/fps, loop=0)   
実行結果

UFOが追加された動画が保存されます。
f:id:T_A_T:20220122144101g:plain

以下のサイトを参考にさせていただきました

Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村

行ったり来たりする動画を作る

 途中で行ったり来たりする動画を作ります。動画の特定区間で逆再生-順再生を繰り返します。画像処理ライブラリOpenCVで動画ファイルを読み出し、全フレームを画像としていったん保存します。その画像をつなぎ合わせて行ったり来たりする動画を作ります。

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
  • OpenCV 4.0.1
準備

 動画ファイルは動画ACの「サッカーでs字の練習する男の子」をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’1636_640x360.mov'で保存しました(動画のサイズは640x360)。このブログにはmovファイルが貼れないのでアニメーションgifファイルに変換したもの。容量の制限があるためサイズを320x180に変換しています。

f:id:T_A_T:20220121193837g:plain
1636_640x360.mov(320x180にリサイズしアニメーションgifに変換したもの)

コード

①最終フレームから100フレーム前まで普通に再生②最終フレームから100フレーム前に来たところで25フレーム逆再生し25フレーム順再生。これを3回繰り返す。③最終フレームまで普通に再生、として行ったり来たりする動画にしてmp4ファイルとgifアニメーションで保存します。なお保存する動画のフレームサイズはもとの640x360を縦横半分の320x180にしています。

from PIL import Image
import cv2

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 動画ファイルのキャプチャー
cap = cv2.VideoCapture('1636_640x360.mov')

# フレームの幅取得
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('back_and_forth.mp4', fourcc, fps, (int(width/2), int(height/2))) 

# 動画を1コマずつ取り込んで処理
while(cap.isOpened()): 
    ret, frame = cap.read() # キャプチャー画像の取り込み
    
    if ret==True: # キャプチャー画像がある場合
        
        # 縦横半分にリサイズ
        resize = cv2.resize(frame, (int(width/2), int(height/2)))
        
        # リストに追加
        frames.append(resize)        
        
    else: # キャプチャー画像がない場合はループ終了 
        break
        
cap.release() # 再生画像をクローズ

p1 = allframes-100 # 折り返すフレーム
p2 = allframes-125 # 折り返すフレーム

for i in range(p1):
    out.write(frames[i])
    # opencvからpillow形式に変換しgifファイル作成用リストimagesに追加
    matrix_pil = Image.fromarray(cv2.cvtColor(frames[i], cv2.COLOR_BGR2RGB))
    images.append(matrix_pil)
    
for j in range(3):    
    for i in range(p1, p2, -1):
        out.write(frames[i])
        # opencvからpillow形式に変換しgifファイル作成用リストimagesに追加
        matrix_pil = Image.fromarray(cv2.cvtColor(frames[i], cv2.COLOR_BGR2RGB))
        images.append(matrix_pil)
        
    for i in range(p2, p1):
        out.write(frames[i])
        # opencvからpillow形式に変換しgifファイル作成用リストimagesに追加
        matrix_pil = Image.fromarray(cv2.cvtColor(frames[i], cv2.COLOR_BGR2RGB))
        images.append(matrix_pil)
    
for i in range(p1, allframes):
    out.write(frames[i])
    # opencvからpillow形式に変換しgifファイル作成用リストimagesに追加
    im = Image.fromarray(cv2.cvtColor(frames[i], cv2.COLOR_BGR2RGB))
    images.append(im)
    
    
out.release() # 出力動画ファイルをクローズ

# gif動画保存
images[0].save('back_and_forth.gif', save_all=True, append_images=images[1:], 
               optimize=False, duration=1000/fps, loop=0)   
実行結果

行ったり来たりする動画が保存されます。
f:id:T_A_T:20220121194542g:plain

以下のサイトを参考にさせていただきました

Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村