InvSR による動画品質改善(ソースコードと実行結果)

概要

InvSR(Arbitrary-steps Image Super-resolution via Diffusion Inversion)は、大規模な事前学習済み拡散モデルが持つ画像の知識を利用して超解像を行う技術である。サンプリング回数を1回から5回の範囲で選べる点に特徴がある。本ページでは、Windows上でのPython開発環境の準備から、動画の各フレームにInvSRを適用して品質を改善するプログラムの実行までを扱う。


画質改善前

画質改善後

目次

関連する外部ページ

サイト内の関連情報

1. Python開発環境,ライブラリ類

ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.html で解説している。

2. Python 3.12 のインストール

Pythonのインストールを行い、Pythonのプログラムを実行する環境を整える。扱う環境は、Windows搭載パソコンである。金子研究室では、Python 3.12.10を推奨する。

[Windows での Python 3.12 のインストール手順を見るには、ここをクリック]

Windows での Python 3.12 のインストール

以下のいずれかの方法でPython 3.12をインストールする。Pythonがインストール済みの場合、この手順は不要である。

方法 1:winget によるインストール

インストールコマンドの実行方法

管理者権限コマンドプロンプトを起動する(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして、コマンド全体をコマンドプロンプトにコピー&ペーストする。

--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動するとPATHが反映される。

REM Python 3.12 をシステム領域にインストール
winget install --id Python.Python.3.12 -e --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1 Include_launcher=1 InstallLauncherAllUsers=1 TargetDir=\"C:\Program Files\Python312\""

REM Python と Scripts を PATH 先頭に追加
powershell -NoProfile -Command "$p='C:\Program Files\Python312'; $s=\"$p\Scripts\"; $c=[Environment]::GetEnvironmentVariable('Path','Machine'); if((Test-Path $p) -and (';'+$c+';' -notlike \"*;$p;*\") -and (';'+$c+';' -notlike \"*;$s;*\")){[Environment]::SetEnvironmentVariable('Path',\"$p;$s;$c\",'Machine')}"

方法 2:インストーラーによるインストール

  1. Python公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンからWindows用インストーラーをダウンロードする。
  2. ダウンロードしたインストーラーを実行する。
  3. 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから python コマンドを実行できない。
  4. 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。

インストールの確認

コマンドプロンプトで以下を実行する。

python --version

バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。

3. Python の開発環境 Visual Studio Code のインストールと Python 用の設定

Python の開発環境Visual Studio Code(プログラムを編集するソフトウェア。以下、VS Code)を整える。

[Windows での Visual Studio Code のインストールと Python 用の設定手順を見るには、ここをクリック]

Windows での Visual Studio Code のインストールと Python 用の設定手順

1. VS Code と拡張機能のインストール

以下のコマンドにより,既存の VS Code を削除し,全ユーザー共有の設定で再インストールしたうえで,拡張機能(VS Code に機能を追加するソフトウェア)をまとめて導入する.

インストールコマンドの実行方法

管理者権限コマンドプロンプトを起動する(手順:Windows キーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして,コマンド全体をコマンドプロンプトにコピー&ペーストする。

インストールコマンド


REM ============================================================
REM Microsoft Visual Studio Code
REM ============================================================
winget uninstall -e --id Microsoft.VisualStudioCode --silent --disable-interactivity --accept-source-agreements
rmdir /s /q C:\ProgramData\vscode-extensions 2>nul
rmdir /s /q "%APPDATA%\Code" 2>nul
rmdir /s /q "%USERPROFILE%\.vscode" 2>nul
rmdir /s /q "%LOCALAPPDATA%\Microsoft\vscode-update" 2>nul

REM VS Code をシステム領域に新規インストール
winget install --scope machine --id Microsoft.VisualStudioCode -e --silent --accept-source-agreements --accept-package-agreements

REM 全ユーザー共有の拡張機能フォルダ
mkdir C:\ProgramData\vscode-extensions 2>nul
icacls "C:\ProgramData\vscode-extensions" /grant "Everyone:(OI)(CI)M" /T

REM スタートメニューのショートカットを --extensions-dir 付きで再作成
rmdir /s /q "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code" 2>nul
del "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk" 2>nul
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); $lnk.TargetPath='C:\Program Files\Microsoft VS Code\Code.exe'; $lnk.Arguments='--extensions-dir \"C:\ProgramData\vscode-extensions\"'; $lnk.Save()"
REM ショートカットの検証
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); Write-Host 'TargetPath:' $lnk.TargetPath; Write-Host 'Arguments:' $lnk.Arguments"

REM ファイル / フォルダ右クリックの「Code で開く」を登録
reg add "HKLM\SOFTWARE\Classes\*\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\Background\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%V\"" /f

REM --extensions-dir 付きで起動する code.cmd ラッパを作成
REM (%* を echo で書くと対話的 cmd で失われるため、PowerShell で [char]37+'*' を書き出す)
powershell -NoProfile -Command "$pct=[char]37; $q=[char]34; $c='@echo off'+[char]13+[char]10+$q+'C:\Program Files\Microsoft VS Code\bin\code.cmd'+$q+' --extensions-dir '+$q+'C:\ProgramData\vscode-extensions'+$q+' '+$pct+'*'+[char]13+[char]10; [IO.File]::WriteAllText('C:\ProgramData\vscode-extensions\vscode.cmd',$c,[Text.Encoding]::ASCII)"

REM 拡張機能のインストール
set "CODE=C:\Program Files\Microsoft VS Code\bin\code.cmd"
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot-chat
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.python
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.vscode-pylance
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.debugpy
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension MS-CEINTL.vscode-language-pack-ja
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension saoudrizwan.claude-dev
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension rust-lang.rust-analyzer
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension tamasfe.even-better-toml
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension anthropic.claude-code
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension almenon.arepl
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --list-extensions --show-versions
echo === セットアップ完了 ===

2. Python インタプリタの選択

同一マシンに複数の Python がインストールされている場合,VS Code で使用する Python 本体(インタプリタ:Python プログラムを解釈・実行するソフトウェア)を選択する必要がある.

  1. コマンドパレット(コマンド名で機能を呼び出す VS Code の入力欄)を開く(Ctrl+Shift+P
  2. Python: Select Interpreter と入力する
  3. 表示される一覧から,使用する Python(例:C:\Program Files\Python312\python.exe)を選択する.

4. 必要なソフトウェアとライブラリのインストール

InvSRは、公開されているプログラム一式を取得して使う。取得にはGitを使うため、Gitが入っていない場合は先にインストールする。

Git のインストール(Windows 上) [クリックして展開]

管理者権限コマンドプロンプトを起動する (手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。

管理者権限は、winget の --scope machine オプションでシステム全体にインストールするために必要となる。

REM Git をシステム領域にインストール
winget install --scope machine --id Git.Git -e --silent --disable-interactivity --force --accept-source-agreements --accept-package-agreements --override "/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS=""icons,ext\reg\shellhere,assoc,assoc_sh"" /o:PathOption=Cmd /o:CRLFOption=CRLFCommitAsIs /o:BashTerminalOption=MinTTY /o:DefaultBranchOption=main /o:EditorOption=VIM /o:SSHOption=OpenSSH /o:UseCredentialManager=Enabled /o:PerformanceTweaksFSCache=Enabled /o:EnableSymlinks=Disabled /o:EnableFSMonitor=Disabled"

必要なライブラリをシステム領域にインストール

管理者権限コマンドプロンプトを起動する (手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。

次のコマンドを実行する。--no-user オプションは、ユーザ領域ではなくシステム領域へインストールするために付ける。InvSRは専用に手を加えた diffusers を同梱しており、pip install -e でその diffusers を導入する。

REM PyTorch をインストール(GPU対応版)
set "CUDA_TAG=cu128"
set "PYTHON_PATH=C:\Program Files\Python312"
"%PYTHON_PATH%\Scripts\pip" install --no-user -U numpy torch torchvision torchaudio --index-url https://download.pytorch.org/whl/%CUDA_TAG%
REM InvSR 本体と依存パッケージをインストール
git clone https://github.com/zsyOAOA/InvSR.git
cd InvSR
pip install --no-user -e ".[torch]"
pip install --no-user -r requirements.txt
cd ..
pip install --no-user -U "opencv-python>=5.0.0" numpy pillow

InvSRの処理はCUDA対応のNVIDIA GPUが必要である。公式の実装が、拡散モデルをGPU上の半精度(16ビット浮動小数点数)で動かす前提で書かれているためである。

5. InvSR 動画品質改善プログラム

概要

AIの基本的な能力の1つは、既存のデータから学習したパターンや特徴を理解し、新しい表現を生成することである。AIによる画像・動画処理技術の発展により、専門的な技術や経験がなくても、動画の品質改善処理が可能となった。

主要技術

本プログラムは、InvSR(Arbitrary-steps Image Super-resolution via Diffusion Inversion)を用いた動画品質改善システムである [1]。この技術は拡散モデルによる画像超解像処理を動画の各フレームに適用し、動画品質の向上を図る。

InvSRは次の要素で構成される。

大きな画像は分割して処理される(chopping)。分割の大きさが CHOPPING_SIZE である。

参考文献

[1] Z. Yue, K. Liao, and C. C. Loy, "Arbitrary-steps Image Super-resolution via Diffusion Inversion," in Proc. IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2025. https://arxiv.org/abs/2412.09013

ソースコード

# 動画品質改善プログラム (InvSR)
# - プログラム名: InvSR動画品質改善
# - 特徴技術名: InvSR (Arbitrary-steps Image Super-resolution via Diffusion Inversion)
# - 出典: Z. Yue, K. Liao, C. C. Loy, "Arbitrary-steps Image Super-resolution via Diffusion Inversion," CVPR 2025.
# - 出典リポジトリ: https://github.com/zsyOAOA/InvSR
# - 特徴機能: 拡散逆変換による任意ステップ超解像(1-5ステップで劣化画像を高品質化)
# - AI学習済みモデル: noise_predictor_sd_turbo_v5.pth(InvSR用ノイズ予測ネットワーク、拡散逆変換の出発点の推定に使用、URL: https://huggingface.co/OAOA/InvSR/resolve/main/noise_predictor_sd_turbo_v5.pth)、および SD-Turbo(土台となる事前学習済み拡散モデル)
# - 前準備: pip install --no-user -U numpy torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
#           git clone https://github.com/zsyOAOA/InvSR.git
#           cd InvSR
#           pip install --no-user -e ".[torch]"
#           pip install --no-user -r requirements.txt
#           cd ..
#           pip install --no-user -U "opencv-python>=5.0.0" numpy pillow
# - 方式設計:
#   - 関連利用技術: Stable Diffusion Turbo(高速な事前学習拡散モデル)、Diffusion Inversion(拡散過程の逆変換による超解像)、Partial Noise Prediction(拡散モデル中間状態構築戦略)、Deep Noise Predictor(最適ノイズマップ推定ネットワーク)、OpenCV(動画処理とフレーム操作)、Pillow(日本語テキスト描画)
#   - 入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://github.com/opencv/opencv/blob/master/samples/data/vtest.aviを使用)、出力: OpenCV画面に処理結果を表示.OpenCV画面内に処理結果をテキストで表示.さらに,print()で処理結果を表示.プログラム終了時にprint()で表示した処理結果をresult.txtファイルに保存し,「result.txtに保存」したことをprint()で表示.プログラム開始時に,プログラムの概要,ユーザが行う必要がある操作をprint()で表示.
#   - 処理手順: 1.動画をフレーム単位に分解、2.入力解像度の上限に合わせて縮小、3.Partial Noise Predictionによる中間状態構築、4.Deep Noise Predictorを用いたノイズマップ推定、5.任意ステップサンプリングによる超解像実行、6.処理済みフレームの表示
#   - 前処理、後処理: 前処理:フレーム正規化、色空間変換、解像度調整、後処理:Wavelet色補正
#   - 追加処理: 大画像分割処理(GPUメモリ制約に対応するChopping処理)、Tiled VAE
#   - 調整を必要とする設定値: NUM_STEPS(サンプリングステップ数、品質と速度のバランス調整、1-5)、CHOPPING_SIZE(大画像分割サイズ、GPU性能に応じた調整、256推奨)、MAX_RESOLUTION(超解像に入力するフレームの最大解像度、現在512)
# - その他の重要事項: CUDA対応GPUが必要。処理時間は動画長とステップ数に比例するため、リアルタイム処理はできない

import os
import sys
import types
import subprocess
import urllib.request
import time
from datetime import datetime

# torchvision 0.17 で削除された functional_tensor への互換対応(basicsr が参照するため)
try:
    import torchvision.transforms.functional_tensor as _ft  # noqa
except ModuleNotFoundError:
    import torchvision.transforms.functional as _F
    _module = types.ModuleType('torchvision.transforms.functional_tensor')
    _module.rgb_to_grayscale = _F.rgb_to_grayscale
    sys.modules['torchvision.transforms.functional_tensor'] = _module

import cv2
import numpy as np
import torch
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageDraw, ImageFont

# 設定値
NUM_STEPS = 3  # サンプリングステップ数 (1-5)
CHOPPING_SIZE = 256  # 大画像分割サイズ
CHOPPING_BS = 8  # 分割パッチのバッチサイズ(GPUメモリが少ない場合は1にする)
MAX_RESOLUTION = 512  # 超解像に入力するフレームの最大解像度
REPO_URL = 'https://github.com/zsyOAOA/InvSR.git'
REPO_DIR = 'InvSR'
CKPT_URL = 'https://huggingface.co/OAOA/InvSR/resolve/main/noise_predictor_sd_turbo_v5.pth'
CKPT_NAME = 'noise_predictor_sd_turbo_v5.pth'
WEIGHTS_DIR = 'weights'
MAIN_FUNC_DESC = "InvSR品質改善"

# 日本語フォント
FONT_PATH = 'C:/Windows/Fonts/meiryo.ttc'
FONT_SIZE = 20
FONT_COLOR = (0, 255, 0)
TEXT_POSITION = (10, 10)

# ガイダンス表示
print('\n=== InvSR動画品質改善プログラム ===')
print('概要: 拡散逆変換技術により動画の品質を改善します')
print('操作方法:')
print('  q キー: プログラム終了')
print()

# 日本語フォントの確認
if not os.path.exists(FONT_PATH):
    print(f'エラー: 日本語フォントが見つかりません: {FONT_PATH}')
    exit()
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)

# InvSR は拡散モデルを GPU 上の半精度で動かす実装のため、CUDA 対応 GPU が必要
if not torch.cuda.is_available():
    print('エラー: InvSR の実行には CUDA 対応 GPU が必要です')
    exit()
device = torch.device('cuda')
print(f'デバイス: {str(device)}')
torch.backends.cudnn.benchmark = True

# 学習済みモデルの取得
if not os.path.exists(REPO_DIR):
    print('学習済みモデルを取得中...')
    subprocess.run(['git', 'clone', REPO_URL, REPO_DIR], check=True)
    print('取得完了')

# InvSR は設定ファイルと内部モジュールを相対パスで参照するため、作業ディレクトリを移す
os.chdir(REPO_DIR)
sys.path.insert(0, os.getcwd())
print(f'作業ディレクトリ: {os.getcwd()}')

from omegaconf import OmegaConf
from sampler_invsr import InvSamplerSR
from basicsr.utils.download_util import load_file_from_url

# ノイズ予測器の取得
os.makedirs(WEIGHTS_DIR, exist_ok=True)
ckpt_path = os.path.join(WEIGHTS_DIR, CKPT_NAME)
if not os.path.exists(ckpt_path):
    print('ノイズ予測器を取得中...')
    load_file_from_url(url=CKPT_URL, model_dir=WEIGHTS_DIR, progress=True, file_name=CKPT_NAME)
    print('取得完了')

# InvSR の設定(公式 inference_invsr.py と同じ手順で構築)
TIMESTEPS = {
    1: [200],
    2: [200, 100],
    3: [200, 100, 50],
    4: [200, 150, 100, 50],
    5: [250, 200, 150, 100, 50],
}
configs = OmegaConf.load('configs/sample-sd-turbo.yaml')
configs.timesteps = TIMESTEPS[NUM_STEPS]
configs.sd_pipe.params.cache_dir = WEIGHTS_DIR
configs.model_start.ckpt_path = ckpt_path
configs.bs = 1
configs.tiled_vae = True
configs.color_fix = 'wavelet'
configs.basesr.chopping.pch_size = CHOPPING_SIZE
configs.basesr.chopping.extra_bs = CHOPPING_BS
print(f'サンプリングステップ: {configs.timesteps}')

print('InvSR を初期化中...')
sampler = InvSamplerSR(configs)
print('初期化完了')

frame_count = 0
results_log = []

def video_frame_processing(frame):
    global frame_count
    current_time = time.time()
    frame_count += 1

    # 解像度調整
    h, w = frame.shape[:2]
    if max(h, w) > MAX_RESOLUTION:
        scale = MAX_RESOLUTION / max(h, w)
        resized = cv2.resize(frame, (int(w * scale), int(h * scale)))
    else:
        resized = frame

    # 前処理(BGR→RGB、0-1正規化)
    frame_rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
    im_cond = torch.from_numpy(frame_rgb).float().div(255).permute(2, 0, 1).unsqueeze(0).to(device)

    # 推論実行(戻り値は b x h x w x c、0-1、RGB)
    enhanced = sampler.sample_func(im_cond)[0]

    # 後処理(RGB→BGR、uint8化)
    processed_frame = cv2.cvtColor((enhanced * 255).round().astype(np.uint8), cv2.COLOR_RGB2BGR)

    # 日本語テキスト描画
    info_text = f'フレーム: {frame_count} | ステップ数: {NUM_STEPS}'
    img_pil = Image.fromarray(cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img_pil)
    draw.text(TEXT_POSITION, info_text, font=font, fill=FONT_COLOR)
    processed_frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

    result = f'解像度: {resized.shape[1]}x{resized.shape[0]} → {processed_frame.shape[1]}x{processed_frame.shape[0]}'

    return processed_frame, result, current_time

print("0: 動画ファイル")
print("1: カメラ")
print("2: サンプル動画")

choice = input("選択: ")

if choice == '0':
    root = tk.Tk()
    root.withdraw()
    path = filedialog.askopenfilename()
    if not path:
        exit()
    cap = cv2.VideoCapture(path)
elif choice == '1':
    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    if not cap.isOpened():
        cap = cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
else:
    # サンプル動画ダウンロード・処理
    SAMPLE_URL = 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.avi'
    SAMPLE_FILE = 'vtest.avi'
    urllib.request.urlretrieve(SAMPLE_URL, SAMPLE_FILE)
    cap = cv2.VideoCapture(SAMPLE_FILE)

if not cap.isOpened():
    print('動画ファイル・カメラを開けませんでした')
    exit()

# メイン処理
print('\n=== 動画処理開始 ===')
print('操作方法:')
print('  q キー: プログラム終了')
try:
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        processed_frame, result, current_time = video_frame_processing(frame)
        cv2.imshow(MAIN_FUNC_DESC, processed_frame)
        if choice == '1':  # カメラの場合
            print(datetime.fromtimestamp(current_time).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3], result)
        else:  # 動画ファイルの場合
            print(frame_count, result)
        results_log.append(result)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
finally:
    print('\n=== プログラム終了 ===')
    cap.release()
    cv2.destroyAllWindows()

    if results_log:
        with open('result.txt', 'w', encoding='utf-8') as f:
            f.write('=== 結果 ===\n')
            f.write(f'処理フレーム数: {frame_count}\n')
            f.write(f'使用デバイス: {str(device).upper()}\n')
            if device.type == 'cuda':
                f.write(f'GPU: {torch.cuda.get_device_name(0)}\n')
            f.write('\n')
            f.write('\n'.join(results_log))
        print('\n処理結果をresult.txtに保存しました')