研究3:遺伝的アルゴリズムを活用した風景画の複製
・背景と目的
・アプローチ手法
・原理
・可視化方法
・可視化結果
・考察
【アプローチ手法】
参考にさせていただいた記事:https://vigne-cla.com/9-22/#toc7
遺伝的アルゴリズムによる画像複製には、遺伝的アルゴリズム(Genetic Algorithm, GA)による本格的な組合せ最適化が自動でできる無料のPythonパッケージのvcoptを利用します。
画像を複製する基本的な考え方は、図形(ここでは円)を組み合わせることで全体の大枠からイメージを作成していき、多段遺伝的アルゴリズムの適用で細部を作っていく、ということです。
この方法の何が良いのか?といえば、処理する次元(≒ピクセル数)を減らしながらも高精度で画像を複製できることが最大のメリットになります。また、この方法は人間が風景画などを描画する方法に近いため、DCGANやPGGANのような特徴量の一部しか出力に反映されない、ということがないことも大きいメリットになります。
【パッケージのインポート】
import cv2 import numpy as np import numpy.random as nr from copy import deepcopy import matplotlib.pyplot as plt from vcopt import vcopt
【パラメータや初期化など】
#画像読み込みと表示 img = cv2.imread('1.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (w_aim, h_aim)) #マスター画像 img_master = np.ones((h_aim, w_aim, 3), np.uint8) * 128 #マスター遺伝子 para_master = np.array([]) #半径列 w = max(w_aim, h_aim) rs = np.linspace(0, w/2, w*10)[::-1] rs_ = np.zeros(w) rs = np.append(rs, rs_) rs = rs.astype(int)
【確定した遺伝子から画像を生成する関数】
確定した遺伝子をすべて貼る関数 def make_img(para): #定義 num = len(para)//5 img_tmp= np.ones((h_aim, w_aim, 3), int) * 128 para_tmp = deepcopy(para) rs_tmp = deepcopy(rs) #遺伝子の変形 para_tmp = para_tmp.reshape(-1, 5) #遺伝子の分離 points = para_tmp[:, :2] points[:, 0] *= w_aim points[:, 1] *= h_aim points = points.astype(int) #print(points) colors = para_tmp[:, 2:] * 255 colors = colors.astype(int) #print(colors) #貼り付け for i in range(num): if i < len(rs_tmp): point = points[i] color = colors[i] tmp = deepcopy(img_tmp) cv2.circle(tmp, (point[0], point[1]), int(rs_tmp[i]), (int(color[0]), int(color[1]), int(color[2])), thickness=-1) img_tmp = 0.5 * tmp + 0.5 * img_tmp img_tmp = img_tmp.astype(int) return img_tmp #適当な遺伝子を作成して画像を確認 para = nr.rand(5*3) para_master = np.append(para_master, para) img_master = make_img(para_master)
【ある部分遺伝子を貼ってスコアを返す関数】
遺伝的アルゴリズムで用いる評価関数です。任意の長さの候補遺伝子を受け取り、すでに確定しているマスター画像に貼り、複製元画像との差をスコアとして返します。
#ある部分遺伝子を貼ってスコアを返す関数 def paste_score(para, visible=False): #定義 num = len(para)//5 img_tmp = deepcopy(img_master) para_tmp = deepcopy(para) rs_tmp = rs[step:min(step + num, len(rs))] #遺伝子の変形 para_tmp = para_tmp.reshape(-1, 5) #遺伝子の分離 points = para_tmp[:, :2] points[:, 0] *= w_aim points[:, 1] *= h_aim points = points.astype(int) #print(points) colors = para_tmp[:, 2:] * 255 colors = colors.astype(int) #print(colors) #貼り付け for i in range(num): point = points[i] color = colors[i] tmp = deepcopy(img_tmp) cv2.circle(tmp, (point[0], point[1]), int(rs_tmp[i]), (int(color[0]), int(color[1]), int(color[2])), thickness=-1) img_tmp = 0.5*tmp + 0.5*img_tmp img_tmp = img_tmp.astype(int) #スコア diff = (img - img_tmp)**2 diff = np.mean(diff)**0.5 return diff #新しい遺伝子を貼り込み step = 3 para = nr.rand(5*3) score = paste_score(para, True) #マスター遺伝子とマスター画像を更新 para_master = np.append(para_master, para) img_master = make_img(para_master) #また新しい遺伝子を貼り込み step = 6 para = nr.rand(5*3) score = paste_score(para, True)
【多段階遺伝的アルゴリズムで最適化】
1ステップでは3個の円を貼る作業を最適化します。これを半径列が尽きるまで繰り返します。
def GA_step(img_master, para_master, step): #パラメータ範囲 para_range = np.zeros((5*3, 2)) para_range[:, 0] = 0 para_range[:, 1] = 1 #print(para_range) #GAで最適化 para, score = vcopt().rcGA(para_range, #パラメータ範囲 paste_score, #評価関数 0, #目標値 pool_num=50, #個体数 max_gen=10000, #進化世代数 show_pool_func='bar') #バー出力を使う #ステップを更新 step += 3 print(step) #マスター遺伝子を更新 para_master = np.append(para_master, para) #print(para_master) #マスター画像を更新 img_master = make_img(para_master) return img_master, para_master, step #ステップの初期化 step = 0 generation = 0 # 世代数のカウンタを追加 #多段階GA開始 while step < len(rs) - 3: #1段階進める img_master, para_master, step = GA_step(img_master, para_master, step) # 世代数をインクリメント generation += 1 # 世代数を表示 print(f"Generation: {generation}") # 生成した画像をファイルに保存するパス output_image_path = "generated_image.png" # 保存先のパスを指定してください # 画像をファイルに保存 cv2.imwrite(output_image_path, img_master)
以上です。