Pythonでいろいろやってみる

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

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初心者にオススメ】音声合成を使って好きな言葉(テキスト)をしゃべらせる(すぐにできます)

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

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

動画を途中からスローモーションにする

動画を途中からスローモーションにします。動画を読み出して、指定した時間以降で同じフレームを10コマ連続させて再び動画にすることでスローモーションにします。画像処理ライブラリOpenCVの cv2.VideoCapture で長さ5秒の動画ファイルを読み出し cv2.VideoWriter で動画に保存しますが4秒以降は同じフレームを10回繰り返します。

関連記事

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

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 6.4.6
  • Python 3.8.12
  • Pillow 9.0.0
  • OpenCV 4.5.5
準備

動画ファイルはMixkitの 'Intense mixed martial arts combat between two women' をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名 ’boxing.mp4' で保存しました(動画のサイズは480x270)。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを下に貼ります。

f:id:T_A_T:20220201214920g:plain
boxing.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)      
実行結果

ラストがスローモーションになった動画が保存されます。
f:id:T_A_T:20220201215231g:plain]

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

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

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

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

動画からサムネイルを作る

 動画から指定のフレームを切り出し文字を入れてサムネイルを作ります。動画ファイルを読み出しキャプチャーした画像の明度と彩度を強調し派手にしたうえで、縁取りの大きな文字で動画タイトルを入れます。画像のサイズをYoutube推奨カスタムサムネイルサイズの1280,x720にリサイズしてjpegで保存します。動画ファイルの読み出し、指定した秒数のフレームのキャプチャー、明度と彩度の強調は画像処理ライブラリOpenCVで行い、タイトル文字の描画とリサイズを画像処理ライブラリPillowで行います(OpenCVでは日本語を描画できないため)。

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

 動画ファイルは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ファイルで保存されます。
f:id:T_A_T:20220129111451j:plain

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

PythonとRPAで遊ぶ > Python OpenCV - 動画のサムネイルを作る
Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【Pillow】ImageDraw.textによる文字の描画

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

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

画像ファイルを指定したファイルサイズまで自動で圧縮する

 画像ファイルをメールに添付する場合など容量制限があるときに、手動でサイズ調整するのは面倒です。画像処理ライブラリ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がデフォルト。
関連記事

Jpeg画像のファイルサイズを小さくする

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

 画像ファイルはフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名'books.jpg'で保存しました。画像サイズ1600x1071px、ファイルサイズは600kBです。
f:id:T_A_T:20220127204052j:plain

コード

 画像の縦横のピクセル数は元のまま、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です。
f:id:T_A_T:20220127204226j:plain

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

note.nkmk.me > Pythonでファイル、ディレクトリ(フォルダ)のサイズを取得

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

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

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

 動画を明るく鮮やかにします。画像処理ライブラリ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技術ブログへ
にほんブログ村