Python で画像フィルタパラメータを blackbox 最適化で探索してみるメモ
背景
対象の関数(問題)がブラックボックス的なものですと, そのパラメータを求めるのは
blackbox 最適化や, 機械学習の分野では hyperparameter 最適化(探索)と呼ばれているようですね.
画像処理でも blackbox 最適化をしたい要求がよくあります.
たとえば, ターゲットとなるオシャンティな画像(インスタ映え画像)に見た目を合わせて, 自分のとったちょっとイマイチな写真でもオシャンティな画像にしたいとか. この場合, 明るさとか, セピア調/フィルム調フィルタとかのフィルタパラメータを探索します.
(手動で見つけるだと無限に時間が溶けてしまいつらい)
今回はもう少し問題を単純化して, ImageMagick でブラーをかけた画像で, そのブラーのパラメータを推定してみます.
画像の誤差にはとりあえず RMSE を使ってみます
(一致するほど値が低くなる)
Python で blackbox 関数の最適化をするメモ
https://qiita.com/syoyo/items/6c33acb0fd475e651f2f
Python で外部プログラムを実行して結果の行をパースするメモ
https://qiita.com/syoyo/items/d13af423604192cee41c
を参考にして, 外部コマンドで ImageMagick を動かし, benderopt で最適化してみます.
データとコード
ぼかし前
ぼかし後
(-blur 27x20
)
from benderopt import minimize
import numpy as np
import logging
import subprocess
import parse
logging.basicConfig(level=logging.DEBUG) # logging.INFO will print less information
blurred_filename = "shimokita-blur.jpg" # convert -blur 27x20
ref_filename = "shimokita.jpeg"
k_num_eval = 10000
def extract_result(lines):
for line in lines:
print(line.decode("utf-8"))
ret = parse.parse("{:g} ({:g})", line.decode("utf-8"))
if ret:
return ret[0]
raise RuntimeError("Failed to extract value from result.")
count = 0
def f(radius, sigma):
global count
count += 1
print("run {} of {} ...".format(count, k_num_eval))
tmp_filename = "shimokita-tmp.jpg"
cmd = "convert {} -blur {}x{} {}".format(ref_filename, radius, sigma, tmp_filename)
ret = subprocess.run(cmd, shell=True)
# Compare two images using RMSE
cmp_cmd = "compare -metric rmse {} {} null:".format(tmp_filename, blurred_filename)
ret = subprocess.run(cmp_cmd, shell=True, capture_output=True)
# `compare`(ImageMagick) outputs result into stderr, not stdout
lines = ret.stderr.splitlines()
val = extract_result(lines)
return val
# We define the parameters we want to optimize:
optimization_problem_parameters = [
{
"name": "radius",
"category": "uniform",
"search_space": {
"low": 0,
"high": 100,
}
},
{
"name": "sigma",
"category": "uniform",
"search_space": {
"low": 0,
"high": 100,
}
}
]
# We launch the optimization
best_sample = minimize(f, optimization_problem_parameters, number_of_evaluation=k_num_eval)
print("radius", best_sample["radius"])
print("sigma", best_sample["sigma"])
print("err = ", f(best_sample["radius"], best_sample["sigma"]))
結果
10,000 回まわしました.
radius 27.993241302558445
sigma 19.957452459359814
err = 49.5512
Voila!
radius は 27(真値), 28(推定値)と 1 違いますが, それなりに真値に近しい結果が得られました.
idiff で差分を取ってみます.
(差分を 20 倍. 差分等倍だと視覚的にはほぼ真っ黒(= 一致))
jpg 圧縮の影響が大きそうですね...
ちなみに 100 回では全然だめで, 1000 回でまあまあそこそこ近い, という結果でした.
TODO
- Bayesian Optimization など試したい.
- 画像の場合は非圧縮形式(PNG, BMP, TIFF)でやりましょう.
- ファイルに結果を書くタイプだと, ディスク I/O 消費が気になる(SSD だと寿命が縮まりそう?)ので memdisk を使えるか考えてみる
- benderopt は並列処理に対応していないので, 非マルチスレッドな外部プログラムを実行だと処理時間がかかってしまうので並列化できるライブラリの利用を検討します.
- 同様のやりかたで Photoshop あたりを操作してインスタ映え画像の生成を極める(コマンドライン制御できたような)
Author And Source
この問題について(Python で画像フィルタパラメータを blackbox 最適化で探索してみるメモ), 我々は、より多くの情報をここで見つけました https://qiita.com/syoyo/items/9cbb966da8541fbd8ed7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .