はじめに
おはこんばんにちは。普段写真を編集することを趣味としているのですが、その過程でどうしても自分で画僧にフィルムカメラで撮ったようなノイズを付与するスクリプトを書いてみたくなったため書きました。
しかし筆者はプログラミング初心者であるため、あまりコーディングに自信がなく、こうして公開することでブラッシュアップをしていただけたらな、同志を募ってモチベーションを高めていきたいなと思いまして、この記事を執筆するに至りました。ちなみにMarkdown記法ですらかなり苦戦しています。スペース打たないとでっかくならないんですね。
仕様
インポートするライブラリ
import os
import tkinter
from tkinter import filedialog
import cv2
import numpy as np
共有変数
file_types = [("JPEG files", "*.jpg;*.jpeg"), ("All files", "*")]
initial_dir = os.path.abspath(os.path.dirname(__file__))
noise_strength = 120
filter_strength = 20
alpha = 0.05
スクリプト
def load_image():
try:
root = tkinter.Tk()
root.withdraw()
# 画像のパスを取得
file_path = filedialog.askopenfilename(filetypes=file_types, initialdir=initial_dir)
original_image_bgr = cv2.imread(file_path)
return original_image_bgr
except Exception as e:
print(f"An error occurred: {e}")
return None
def convert_to_vector(original_image):
return np.asarray(original_image)
def extract_channels(image_vector):
r_channel = image_vector[:, :, 2]
g_channel = image_vector[:, :, 1]
b_channel = image_vector[:, :, 0]
return r_channel, g_channel, b_channel
def generate_noise(original_image):
# original_image の範囲でノイズを生成
noise = np.random.randint(-noise_strength, noise_strength + 1, original_image.shape[:2])
print(f"Original Noise Shape: {noise.shape}")
# original_image と同じサイズにリサイズ
noise = cv2.resize(noise, (original_image.shape[1], original_image.shape[0]))
print(f"Resized Noise Shape: {noise.shape}")
# ノイズの形状を (height, width, 1) から (height, width, 3) に変更
noise = np.stack([noise] * 3, axis=-1)
print(f"Final Noise Shape: {noise.shape}")
return noise
def convert_to_monochrome(noise):
# ノイズをモノクロに変換
monochrome_noise = np.mean(noise, axis=2, keepdims=True)
print(noise.shape)#OK
return monochrome_noise
def apply_blur(noise):
# デバッグ用にノイズの形状を印字
print(f"Noise before blur: {noise.shape}")
# 平均値フィルタをかける
return cv2.blur(noise, (filter_strength, filter_strength))
def composite_images(original_image, noise):
# 合成する
print(f"Original Image Shape: {original_image.shape}")
print(f"Noise Shape: {noise.shape}")
# ノイズを (height, width, 3) の形に変形
noise_expanded = np.repeat(noise[:, :, np.newaxis], 3, axis=-1)
# noise_expanded を original_image と同じ型に変換
noise_expanded = noise_expanded.astype(original_image.dtype)
composite_image = cv2.addWeighted(original_image, 1 - alpha, noise_expanded, alpha, 0)
composite_image = np.clip(composite_image, 0, 255).astype(np.uint8)
return composite_image
def save_image(image, filename):
cv2.imwrite(filename, image)
def show_image(image, window_name='Image'):
cv2.imshow(window_name, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
original_image = load_image()
if original_image is not None:
image_vector = convert_to_vector(original_image)
r_channel, g_channel, b_channel = extract_channels(image_vector)
# Gチャンネルの輝度に基づいてノイズを生成
noise = generate_noise(original_image)
# ノイズをモノクロに変換
monochrome_noise = convert_to_monochrome(noise)
# 平均値フィルタをかける
blurred_noise = apply_blur(monochrome_noise)
# ノイズと元の画像を合成
composite_image = composite_images(original_image, blurred_noise)
cv2.imwrite('composite_image.jpg', composite_image)
show_image(composite_image, 'Composite Image')
個人的によりこだわりたいところ
・おそらくノイズ生成、合成の次元をそろえる部分がかなり迷宮入りしているため、きれいにしたい。
・取得した画像から輝度を取得し、それを10段階程度に分割してそれそれの段階に応じて個別に任意のノイズ強度を設定できるようにしたい。またそれを行った際に起こるノイズの境界部分の急激なノイズの変化についてはいい感じになだらかにしたい。
以上であります。コメント、ご連絡お待ちしております。