MENU

【Python】AIを使った写真のノイズ除去ツールを自作しよう

撮影した写真がノイズだらけになったことは、ありませんか?最近では、AIを活用した画像処理の一環として、AIを使ったノイズ除去サービスが数多く見つかります。

しかし、それらすべては有料であり、気軽にノイズ除去することができません。

もし、あなたがGPUを搭載したゲーミングPCやクリエィティブPCを使っていたなら、AI(深層学習)を使った画像のノイズ除去を無料で行えるようになります。しかも有料サービスに引けを取らないくらい高品質です。

今回は、AIを使って写真のノイズを効果的に除去できる「画像ノイズ除去ツール」を自作しましたので、その性能とソースコードを紹介します。

GPUを使うために環境構築は少々難易度が上がりますが、効果絶大ですので、是非挑戦してみてください。

目次

写真ノイズ除去ツールの概要

今回紹介するノイズ除去ツールには、次の特徴があります。

  • ノイズ除去のAIアルゴリズム SCUNetを使用することで、効率的にノイズ除去できます。
  • 指定したフォルダの画像ファイルを、まとめてノイズ除去します。
  • ノイズの状態や仕上がり具合に応じて、5つのAIモデルが選択できます。
  • Pythonのバッチファイルとして、ノイズ除去を実行することが可能です。

SCUNetとは

引用元:https://github.com/cszn/SCUNet

SCUNETは、画像処理分野で利用されるディープラーニングベースのモデルで、特にノイズ除去や画像の復元に優れています。SCUNETは畳み込みニューラルネットワーク(CNN)の一種であり、画像内の不要なノイズを除去しながら、元のディテールを保持することを目的としています。

詳細とインストール手順は、SCUNetの公式GitHubにて公開されており、本ブログはこのGitHubで公開されているモジュールやモデルを呼び出して使用しています。

写真ノイズ除去ツールの使い方

画面項目の説明

画面項目説明
入力フォルダノイズ除去したい画像ファイルを格納したフォルダのパス
画質選択ノイズ除去の画質の次の中から選択。
質感優先:質感を重視し、自然な感じでノイズを除去。人物などに最適。
ディテール優先:ディテールを優先し、最大限ノイズを除去。人工物に最適。
ノイズ少:ノイズが少ない写真(ISO感度100~400)
ノイズ中:全体的にノイズが目立つ写真(ISO感度800~3200)
ノイズ多:かなりノイズ量が多い(ISO感度 6400~)
出力フォルダノイズ除去済み画像ファイルの保存先フォルダのパス
ノイズ除去の実行ボタンノイズ除去の実行

ノイズ除去手順

  • ノイズ除去したい画像ファイルが保存されているフォルダを指定します。
  • 画質の状態に応じて、画質を選択します。
  • ノイズ除去した画像ファイルを保存したいフォルダを指定します。
  • 「ノイズ除去の実行」ボタンをクリックします。

バッチ処理

UIを使わず、denise.py をバッチ処理として動作させることも可能です。この場合は、以下の様に起動時にパラメータを指定します。

python denise.py --input_folder 入力フォルダ名 --output_folder 出力フォルダ名 --model_name モデル名

引数名デフォルト値説明
--model_namescunet_color_real_gan使用するモデルの名前を、次の5種類から選択する。
scunet_color_real_gan
scunet_color_real_psnr
scunet_color_15
scunet_color_25
scunet_color_50
--input_folder必須入力画像のフォルダ
--output_folder必須処理結果の保存先フォルダ
--model_zoomodel_zooモデルの保存場所

python denise.py --input_folder O:\DeNise\testsets\best --output_folder O:\DeNise\res --model scunet_color_real_gan

プログラムのダウンロードと動作環境の設定

NVidia 製のGPU(RTX-2000シリーズ、RTX-3000シリーズ、RTX4000シリーズ,RTX-5000シリーズ)がPC本体に内容(装着)されていることが前提となります。CPUだけでも動作するかもしれませんが、とてつもなく遅いのでお勧めできません。

STEP
Pythonのインストール

事前に、Pythonのインストールが必要です。まだ環境構築が済んでいない方は、下記の記事を参考に構築してください。

ポータブルPython開発環境の作り方(WinPython)プログラム実行時に必要
WinPythonにGit Portable版をインストールするAI関連インストール時に必要
WinPythonにVSCode Portable版をインストールするプログラム修正時に必要
STEP
ライブラリのインストール

Python 環境に下記のライブラリをインストールします。 command.bat を実行後、下記のコマンドを実行します。

pip install customtkinter
pip install tkinterdnd2

STEP
AIモデル「SCUNet」及び関連ライブラリのインストール

今回はSCUNetというAIモデルを使うので、必要なファイルをインストールしていきましょう。下記のコマンドを1つづつ実行してください。

SCUNetに関する詳細とインストール方法については、下記のブログ記事に詳しく掲載されていますので、参考にしてください。
【Python】無料だけど凄い!AI「SCUNet」による写真/画像ノイズの除去方法を解説

git clone https://github.com/cszn/SCUNet.git
cd SCUNet
pip install thop
pip install einops
pip install timm
pip install opencv-python
pip install matplotlib
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
python main_download_pretrained_models.py --models "SCUNet" --model_dir "model_zoo"

STEP
ソースコードのダウンロードと展開

libs.zip はSCUNetフォルダと同一階層になるように解凍してください。
また、denose.zipに含まれる3つのファイルを、SCUNetフォルダ直下にコピーしてください。

STEP
フォルダ名の変更

SCUNet というフォルダ名は、そのままでも問題ありませんが、例えば denise のようにフォルダ名を変更しておくと、後で分かり易くなるかと思います。

実行方法

次の手順で実行してください。

  • WinPython のインストールフォルダ内にある command.bat を実行
  • SCUNetをインストールしたフォルダ(denise.py やmain.pyをコピーしたフォルダ)に移動
  • Python main.py を実行

python main.py

しばらくすると下記の画面が表示されます。必要な箇所を入力してください。入力/選択した内容はプログラム終了時も保持され、次回起動時に表示されます。

実行すると、コマンドプロンプトにノイズ除去されたファイル名と処理時間が表示されます。

写真ノイズ除去ツールの仕様

プログラムの構成

main.py の中で画面の表示と「ノイズ除去の実行」ボタンのイベント処理を記述しています。イベント処理の中でdenise.pyを呼び出し、その中から 「SCUNet」関連のモジュールを呼び出しています。

モジュール名役割
main.py画面の表示とボタンクリックのイベント処理
denise.pyCSUNetで公開されているモジュールを呼び出しながら、ノイズ除去を行う
create_ui.pyUI定義ファイルを読み込み、記述されたウィジェットを画面表示
customtkinterファイル選択やフォルダ選択、ドラッグ&ドロップを実現するための補助
appconfig.py画面に入力された値をJson形式のファイルに保存/読込する

ソースコード

main.py

UI画面の表示と「ノイズ除去の実行」ボタンの処理が記述されています。

       
import os
import sys
sys.path.append(os.path.join(os.path. dirname(__file__), '../libs'))
from create_ui import CreateUI
import torch
from denise import *

# ボタンが押された時の処理
def func(param):
    input_folder = param["input_folder"]
    output_folder = param["output_folder"]
    model_combo = param["model_combo"]

    model_path = ""
    if(model_combo == "質感優先") :
        model_path = "scunet_color_real_gan"
    elif(model_combo == "ディテール優先") :
        model_path = "scunet_color_real_psnr"
    elif(model_combo == "ノイズ少") :
        model_path = "scunet_color_15"
    elif(model_combo == "ノイズ中") :
        model_path = "scunet_color_25"
    elif(model_combo == "ノイズ多") :
        model_path = "scunet_color_50"  
         
    denoise_image(model_path, input_folder, output_folder)

# インスタンス生成
ui = CreateUI(func)


# 画面の表示
ui.show()

denise.py

このファイルには、次の4つの関数が含まれています。 
以下は、提供されたソースコードに基づく関数のリファレンスです。

関数名説明
load_model(
model_name, # 使用するモデルの名前
model_zoo, # モデルの保存場所
device, # 使用するデバイス (CPU/GPU)
n_channels=3 # 入力チャンネル数
)
指定されたモデルを読み込み、GPUまたはCPUにロードする。戻り値としてロードされたモデルオブジェクトとそのパスを返す。
process_images(
model, # ロード済みのモデルオブジェクト
input_folder, # 入力画像が保存されているフォルダ
output_folder, # 処理結果の保存先フォルダ
device # 使用するデバイス (CPU/GPU)
)
指定されたフォルダ内の画像をすべて処理し、ノイズ除去を行った結果を output_folder に保存する。処理時間の計測やメモリ管理を実施する。
denoise_image(
model_name='scunet_color_real_gan', # モデル名
input_folder='', # 入力画像フォルダ
output_folder='', # 処理結果の保存先フォルダ
model_zoo='model_zoo' # モデルの保存場所
)
Python 内から直接画像ノイズ除去を実行する関数。エラーチェックを行い、処理対象フォルダが未指定の場合は例外を発生させる。
denoise_batch()コマンドラインからバッチ処理でノイズ除去を実行する。 argparse を使用してパラメータを受け取り、 denoise_image() を呼び出す。
import os
import time
import argparse
import numpy as np
import torch
from utils import utils_model, utils_image as util
from models.network_scunet import SCUNet as net

def load_model(model_name, model_zoo, device, n_channels=3):
    model_path = os.path.join(model_zoo, model_name + '.pth')
    model = net(in_nc=n_channels, config=[4, 4, 4, 4, 4, 4, 4], dim=64)
    model.load_state_dict(torch.load(model_path), strict=True)
    model.eval()
    
    for _, param in model.named_parameters():
        param.requires_grad = False

    return model.to(device), model_path

def process_images(model, input_folder, output_folder, device):
    util.mkdir(output_folder)

    img_paths = util.get_image_paths(input_folder)
    total_images = len(img_paths)

    print(f"処理開始: {total_images} 枚の画像を処理します。")

    start_time = time.time()

    for idx, img_path in enumerate(img_paths):
        img_name, ext = os.path.splitext(os.path.basename(img_path))
        img_L = util.imread_uint(img_path, n_channels=3)
        img_L = util.uint2single(img_L)

        img_L = util.single2tensor4(img_L).to(device)

        # 画像処理の開始時間を計測
        image_start_time = time.time()
        
        # メモリ管理を改善するため test_mode() を使用
        img_E = utils_model.test_mode(model, img_L, refield=64, mode=5)
        img_E = util.tensor2uint(img_E)

        output_path = os.path.join(output_folder, img_name + ext)
        util.imsave(img_E, output_path)
        
        # 画像処理の終了時間を計測
        image_end_time = time.time()
        processing_time = image_end_time - image_start_time

        print(f"{idx + 1}/{total_images} 処理完了: {img_name + ext} (処理時間: {processing_time:.2f} 秒)")

        # メモリ解放
        del img_L, img_E
        torch.cuda.empty_cache()

    end_time = time.time()
    total_processing_time = end_time - start_time

    print(f"全画像処理完了!総処理時間: {total_processing_time:.2f} 秒")

def denoise_image(model_name='scunet_color_real_gan', input_folder='', output_folder='', model_zoo='model_zoo'):
    """ Python プログラム内から直接 denoise を実行する関数 """
    if not input_folder or not output_folder:
        raise ValueError("input_folder と output_folder は指定する必要があります。")

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model, model_path = load_model(model_name, model_zoo, device)

    print(f"モデル使用: {model_name} (パス: {model_path})")
    process_images(model, input_folder, output_folder, device)

def denoise_batch():
    """ コマンドラインからバッチで denoise を実行する関数 """
    parser = argparse.ArgumentParser(description="バッチで画像を処理")
    parser.add_argument('--model_name', type=str, default='scunet_color_real_gan', help="使用するモデルの名前")
    parser.add_argument('--input_folder', type=str, required=True, help="入力画像のフォルダ")
    parser.add_argument('--output_folder', type=str, required=True, help="処理結果の保存先フォルダ")
    parser.add_argument('--model_zoo', type=str, default='model_zoo', help="モデルの保存場所")

    args = parser.parse_args()
    denoise(args.model_name, args.input_folder, args.output_folder, args.model_zoo)

if __name__ == '__main__':
    denoise_batch()

design.txt

title:写真ノイズ除去ツール
mode:light
max:1024,300
size:600,300
min:600,300
input_folder:変換元フォルダ,フォルダ選択
{
    label:   画質選択
    model_combo:質感優先,ディテール優先,ノイズ少,ノイズ中,ノイズ多
}
output_folder:出力先フォルダ,フォルダ選択

exec_button:ノイズ除去の実行

design.txt の記述方法については、下記の記事で詳しく解説しています。

あわせて読みたい
【CustomTkinter】テキスト記述でGUIを簡単作成するライブラリを紹介! 本ブログで紹介しているツールも含め、自作ツールはちょっとした作業を自動化することが目的なので、簡易的な画面で事足りることが大半です。 とはいうものの、CustomTk...

まとめ

今回は、「写真ノイズ除去ツール」について、環境構築の手順と使い方、ソースコードを紹介しました。

今回はAIモデル「SCUNet」を用いているため、NVidia製のGPUが必須となっています。また、AI関連のモジュールを多用するため、インストール手順も少々複雑になってしまいました。

とはいえ、1つづつ実行していけば環境は構築できますので、是非挑戦してみてください。有料サービスに匹敵するノイズ除去が、枚数無制限且つ無料でできるようになります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次