この記事は...
基本的にフィルタ処理を行うことができないウディタ上で,何とか似たようなことができないかと,昨年度末から試行錯誤している人間の備忘録的なものです.
気づいたら前回の記事から三か月たっててビビってます.
前回までの記事
ウディタで画像処理したい(その1
ウディタで画像処理したい(その2
ウディタで画像処理したい(その3
ウディタで画像処理したい(その4
今回は加算表示による平均化フィルタの拡張を行いました.パッと見せられる結果みたいなのがなくて申し訳ありませんが,気になる方は続きからどうぞ.
追記:ブログをまとめてるときにそれなりにいいものが出たので結果として載せときます.
|
|
改良前の平均化処理 |
改良後の平均化処理 |
前回までのおさらい
「フィルタ処理」と銘打ってはいますが,平均化フィルタ(モザイク化)しかできてません.これまでの記事の内容をおさらいすると,ウディタ上で画像に平均化フィルタをかけるためには,
通常表示を用いる方法と加算表示を用いる方法の二つがありました.双方ともに不透明度を弄った画像を複数枚重ねることで,近傍領域の画素値の平均化(したように見える)処理を行うという流れは変わりません.詳しい処理内容は過去記事を参照していただくとして,ここでは簡単な利点と欠点だけ記しておきます.
【通常表示の利点と欠点】
・背面の状態に依存しない
・画像端が自然に仕上がる
・3x3の近傍画素のモザイク化が精一杯
【加算表示利点と欠点】
・通常表示よりも大きな領域の平均化が可能
・背面は真っ黒(理想的には(R,G,B)=(0,0,0))でなければならない.
・画像端が不自然になる可能性がある.
|
|
通常表示ver(3x3) |
加算表示ver(3x3) |
新しく画像を作り直すのが少し面倒だったので過去記事からの引用ですが,通常表示と加算表示によるモザイク化の比較が上の画像です.これだけを見ると,通常表示のほうが自然な仕上がりになっているように見えるので通常表示verだけ使えばいいかなぁなんて思いがちなんですが,上にも記したように3x3領域より広い領域をモザイク化しようとするとうまく働きません.
というのも,通常表示verでは画像をずらして重ねる際に,それぞれの不透明度を
前回表示した画像の不透明度の半分にしているんです.つまりは
255→127→63→31→15→...
というような感じで不透明度が小さくなっていってるんですけど,特殊な処理を挟まずに1/2していくだけだとそもそも9枚目(3x3平均化の最後の画像)の不透明度が0になってしまうんですよね(数値の切り捨てを何とか回避しても9枚目が限界ですかね).したがって,3x3以上の領域の平均化を行おうと引数を与えても,
10枚目以降が表示できないので意味はない...と
その点加算表示verでは,とある画素の画素値はその画素に加算表示されている画像の画素値の総和(えげつないほど読みずらい),要は足し算になります.このとき
各画像の不透明度は255/(重ねたい画像の枚数)となるため,特殊な操作を行わなくても16x16領域(画像の総枚数256枚)くらいまでならそれっぽく処理できます.
とはいえ画像をずらして加算表示しているため,背景が真っ黒でない限りは画像端が不自然に強調されてしまうんですね.(それが上の図の加算表示verからもわかる)
ここまでの話からそれぞれの利用先を考えると,通常表示verは
マップチップやマップ内のオブジェクトのように背面が黒に固定しずらいものへ,加算表示verは
ノベルゲームの背景画像などの背面が黒でも問題なく,且つより広い領域のぼかしが必要なものへ...というのが妥当なところでしょうか.
しかし...マップチップへの平均化処理はたとえ3x3であっても常時実行ではかなり重いので,画面スクロールの無い(あるいはマップサイズが小さく一括で全画像を表示しても重くならない)時くらいしかゲームへの応用はできないですね...かなしい
加算型平均化フィルタ
今回は加算ver改め「加算型平均化フィルタ」について掘り下げて書きたいと思います.
勝手に僕がこう呼んでるだけなので,ほかの人に言わないでください(恥ずかしい^q^)
まずはこちらをどうぞ
|
|
1x1 ~ 9x9 |
10x10 ~ 18x18 |
加算型平均化フィルタで 1x1 から 18x18 領域までを平均化した結果です.アルファベットのZをかくときの筆の流れで画像が順に荒くなっていってます.また二枚目について,6枚しか画像がないように見えますが,最下段は除算の結果透過率が0となってしまっているため見えないだけです.
二枚目の最下段は 16x16 ~ 18~18 領域の平均化の結果ですが,さっきぎりぎり大丈夫と書いたはずの 16 x 16も,どうやらダメっぽいですね(255/256の小数点以下切り捨ては0).ということは 15x15 領域の平均化が限界ということなんでしょうか...?
確認のため不透明度の計算時に最低保証で透過率が1になるように引上処理を加えてみましょうか.
|
|
引き上げ後 10x10 ~ 18x18 |
引き上げ後 19x19 ~ 27x27 |
16x16 は引き上げ処理のおかげで何とか平均化処理として言い張れそうですけど,それ以降は徐々に怪しくなっていって二枚目はほとんど画像が白飛びしちゃってますね.まぁ,本来であれば1未満の不透明度で表示しなければならないとところを1まで引き上げてしまっているので当然といえば当然でしょうが...
しかし,白飛びはしてしまっているものの画像全体を見ると何となく平均化できているようにも見える...これ,何とかできませんかね.
前置きが長くなりましたがここからが本題です.
何とか白飛びを軽減したい
ウディタ側に小数点以下の不透明度を設定できない以上,不透明度の最低値を1に固定したままでどうにか工夫できないでしょうか,ってことでやりました.
|
|
引き上げのみ 19x19 ~ 27x27 |
改良後 19x19 ~ 27x27 |
見た目こそ大きな変化がありますが,やったことは単純です.すべての不透明度が最低1あるせいで画像を重ねた際に白飛びしてしまうなら,オーバーしてしまう分ランダムで消せばいいんじゃない?みたいな.
例えば27x27の場合について考えると,処理上必要な画像の枚数は27x27で729枚です.計算上各画像が持つべき不透明度は0.35程度のところ,不透明度の最小値を1にしてしまっているため画素によっては白飛びが起こってしまうというわけなんですね.そこで,729枚のうちの474枚をランダムで選択して削除することで,疑似的に不透明度の総和を255に近づけ,白飛びのない平均化フィルタを実現する...という感じです.要は,本来周囲729画素の画素値の平均値をとるべきところ,その中の適当な255画素分の平均値で代用しているってこと.
ちなみに今回改良するついでに,不透明度の総和が255よりも少ない場合にも適当な画素の不透明度を少しずつ増やす処理も加えています.
しかしながら,ここまで来たらこれは完全に平均化フィルタではないような気がしてきました.16x16以降は使用している画像の枚数がほとんど変わらないのが(処理の重さを考えた時に)利点といえば利点ですが...改良した平均化処理を使って,さらに大きい領域の処理まで見てみましょうか
|
2x2 , 4x4 , 8x8 , ... , 64x64 |
64x64まで領域を増やしてみましたが,それなりには見えますね.下段はほとんど使用枚数が変化していないということを考えると,コスパはいいのかな...?
でも...気づいちゃったんですけど,これって...ということでおまけです.
平均化処理によって暗くなる画素について
平均化フィルタで本来やりたいことは,周囲の画素との平均をとること.のはずなんですけどどう考えても左上の紫っぽいとこ,途中から暗くなってませんか???
どこからだ~~と適当に探してきました.
|
|
改良前 |
改良後 |
すると,改良前では12x12あたりから,改良後では14x14あたりから暗くなり始めてました.で,いろいろ調べてみたんですけど,これもやっぱり不透明度がらみの問題でした.
(特に詳しく検証はしたわけではないのでここからは話半分で聞いてほしいんですが)
ウディタ上で表示される画像の画素値は,カラー補正を加えていなければ
(本来の画素値)×(不透明度)/ 255
で,その際の小数点以下の扱いは四捨五入のようでした.今回使用した画像の左上の紫部分の画素値は100程度(説明の簡略化のためRの輝度値で説明)なんですけど,この値って
100 ×(1)/ 255 ≒ 0.39 →ウディタ上では 0
100 ×(2)/ 255 ≒ 0.74 →ウディタ上では 1
って感じで,不透明度1だと画素値が0になってしまい,2だとぎりぎり除算後も画素値1としてカウントされるっていう微妙な値でした.つまり,不透明度の計算時に1となってしまった瞬間に画素値100程度の画素は無視されてしまうということなんですね(悲しいね)
処理にもよると思いますが,今回不透明度を計算するときに用いた式は
255 / (使用される画像数)
という単純なものなので,改良前では 11x11 と 12x12 の場合で
255 / 11^ ≒2.11 →ウディタ上では 2
255 / 12^ ≒1.77 →ウディタ上では 1
ってな感じでバッサリと不透明度が変わってしまうため,12x12以降ではうまくいかなかったと.じゃあなんで改良側はうまくいっているのよ..というと,上の方にさらっと書いてありますが全画像の不透明度の合計値が255に満たない時に,ランダムで何枚かの画像の不透明度を+1しているからです.
特に13x13の場合は全画像数が169枚なのに対し,計算上各画像の不透明度は1となってしまうため,画像のうちのおよそ半数に対し不透明度を+1しています.そのため改良後の処理では改良前には描画できなかった画素まで表示できている場合があるというわけです.
処理の改良(案を含む
・カラー補正について
記事をまとめている最中にふと思ったんですけど,これってカラー補正を加えることでより細かな不透明度の調整できませんかね,まだ全然試してないんですけど,もう少しそれっぽく見えるフィルタができるかもしれません.
・使用する画像の画素値について
今回は不透明度の最小値を1として処理を行いました.不透明が1の時,画像中の各画素の画素値は255で割られるため,この際0.5を下回ってしまう画素については描画することができませんでした.しかしこの仕様から逆に考えれば,255で割っても画素値が0.5を下回らない画素が画像の大多数を占めていれば,今回の画像以上に平均化処理がうまくいくんじゃないでしょうか.
実際に計算してみると画素値が128以上あれば,255で割っても四捨五入で1残るようです.そんな画像あるかなぁ...
|
|
改良前マンドリル |
改良後マンドリル |
何となく画素値が高そうなものを持ってきましたが,R,G,Bのどれかが大きくても,そのほかが小さいと,画素値の高い成分が強調されてしまいますね,だんだんとビビッドカラーに近づいていく感じ...そもそも全部の成分が127以上となると,その画像自体がそもそも白飛びしたようなまっしろーーい画像になってしまいそうなので,ダメそうですね...
|
|
改良前バルーン |
改良後バルーン |
いや白っぽい画像でもダメでした.
まぁ小手先の策略では何をやってもダメそうですね,ただ今後も検討の余地はありそうです.
・不透明度の最低値を大きくする
不透明度の最低値が1では,画素値が128未満の画素の描画に失敗してしまう.でも画素値の各成分が128以上の画素のみで構成された画像なんてふつう使わない...ということで,じゃあそもそも不透明度の最低値を大きくすればよいのでは?と思いました.
あれ...不透明度の最低値を大きくしたら割とよく描画できてる気がする...
(最低値3より大きな値にしていないのはテスト段階ということで許してください.)
最低値1だとそれなりで,最低値2だとなんかへんだな~で,最低値3になると急に素直になるのなんなんだ...最低値を上げることで無視される画素の成分が少なくなったおかげで左上の部分だけでなく,画像全体として少しよさげになってしまいました...うそでしょ...
ちなみにこの結果はブログをあらかた書き終わった後取得したので,いろいろ焦ってます.はは
ほかの画像でも一応試してみますか...というわけではい
|
|
マンドリル |
バルーン |
さっきうまくいかない感じだったマンドリルさんはしっかりぼかされてるっぽいですね,ただ,バルーンは改良前よりもうまくいかなかった様子.失敗例が出てほっとしました.
おわりに
今回は,前に作った加算型平均化フィルタの改良と,改良案の模索をしました.
ブログのまとめに入ろうと思った矢先にいきなりいい結果が出てしまったので,次回までにもう少しブラッシュアップして、バルーンちゃんもうまいことぼかせないかやってみます.
みなさんはちゃんとデータを最後まで取ってからブログを書きましょう.
これが論文だったら死んでるとこだった