読者です 読者をやめる 読者になる 読者になる

ぬうぱんの備忘録

技術系のメモとかいろいろ

作った曲一覧はこちら

モザイクのその向こうが見たかったオタクの話

CV C++

この記事は

TUT Advent Calender 2015の参加記事です。今年は準備期間がたっぷりあったので、しっかりとネタを用意しましたよ!

前日の記事

前日の記事はこちら(大学で生き残るための日常生活の過ごし方)

話を始める前に

図とか使ってわかりやすくと思ってたけど計画倒れだこれ!

はじめに

みなさんはえっちコンテンツは好きですか?僕は大好きです。二次元えっちコンテンツ大好き。三次元も10段階評価で6をつけるくらいには好きです。ところで国内のえっちコンテンツには大抵の場合モザイクがかかっていますね? このモザイク、正直言って邪魔な場合が多いですよね? モザイク消したいなって男の子なら一度は思ったことありますよね? このモザ消し…とまでは言わないけど、モザイクを目立たなくしたいなー、よし、やろう! というのがこの記事です。

モザイクの原理

モザイク処理の原理はすっごく単純で

  • 画像をNxNピクセルでグリッド状に分割(ブロック)
  • ブロックごとに平均色を求める
  • ブロックごとに平均色で塗りつぶし

別の言い方をすると「解像度をN/1に下げて元に戻す」という処理でもあります。

つまり、モザイクっていうのは部分的に解像度を落としているっていう事になるんです。
ということは、モザイクを消すっていうのは、低下した解像度を元の高解像度に戻すって言うことになりますよね?
こういう、低解像度画像から高解像度画像を作り出す処理のことを超解像処理と呼んだりします。

超解像でデモザイキング

モザイク除去が一種の超解像処理だということはわかりました。が、この超解像処理がまた難しい。
いろいろな手法があるのですが、今回のケースで適用できそうな「学習ベースの超解像」は

  • モザイクが掛かる前の画像とかけたあとの画像のペア(学習データ)を大量に用意しないといけない
  • 職人技的な学習パラメータの調整を要求される
  • 学習にすっごい時間がかかる

という難点があります。すっごいハードな問題なんです。
3DCGかなにかで学習データを用意できそうな気はしますが…?

そもそも、やろうとしていることが

  • N個のデータを用意
  • データの平均値を求める
  • 平均値から元のN個のデータを推定

というかなり無茶なことですから、難しくて当然ですね。

モザイクを誤魔化すには

計算ずくでオリジナルを推定するのは無茶そうなので、モザイクをごまかす方向で考えてみましょう。
でもごまかすってどうやるんだ…?

全体を低解像度化

さて、そもそもモザイク処理というのは部分的に画像の解像度を落とす処理だということを先に述べました。
なら、全体まるごと解像度を落として部分的な解像度の低下具合が目立たないようにすればいいんじゃね…?
ということで、画像全体にまるごとモザイクを掛けてしまいましょう(!)
モザイクをかけただけだと、元々の画像のディティールとかが失われてしまいそうなので、オリジナル画像と全体モザイク画像を半透明合成でブレンディングしましょう。

チェスボード状輝度補正によるモザイク感低減

実は先行研究(?)として、こんなものがありまして。

画像全体にチェスボード状の明暗をつけることでモザイクが目立たなくなる…というものですね。こんなテクを発見しちゃうなんてえっちゲーム作る人ってすごいとおもった。
これは恐らく、モザイクのブロック単位での明暗とチェスボードによるブロック単位での明暗を同系統のブロック単位の明暗であると人間が錯覚し、「モザイクの大きいブロックサイズ」と「チェスボードの小さいブロックサイズ」を誤認し、結果としてモザイクのブロックサイズが小さくなったと錯覚しているのでしょう。よりブロックサイズの小さいモザイクというのはより薄いモザイクのことですから、モザイクが薄くなったと感じるのでしょう。
というわけで、チェスボードパターンとオリジナル画像を半透明合成する、という方法で実装してみましょう。

境界をぼかす

モザイクがモザイクとして認識される理由の一つとして、ブロックの境界が画像の軸に並行で一定間隔で並んでいるという規則性が考えられます。
ぼかし処理によって、この境界を曖昧にしてモザイクらしさを低減させることができるかもしれませんね?
これは、ボケ具合を調整できるガウス平滑化で実装しましょう。

手法まとめ

さて、じゃあ結局どうするのかというと、

  1. 入力画像から全体にモザイクをかけた画像を生成
  2. チェスボードパターン画像を生成
  3. 入力画像、モザイク画像、チェスボードパターン画像を半透明合成
  4. 半透明合成画像にガウス平滑化をかける

なんだかすごく基本的な画像処理しかないですね。

実験結果

ということで、実際にプログラムを書いて実験してみましょう。
入力画像はアイスを食べるハーピーのパピちゃんです。


f:id:NU_Pan:20151221230130j:plain
か゛わ゛い゛い゛な゛ぁ゛ハ゛ヒ゛ち゛ゃ゛ん゛
ただ、僕はあずきバーが好きなので、あずきバーっぽい色合いにします。

f:id:NU_Pan:20151221230345p:plain
おいしいそうですね。
元画像の圧縮ノイズの関係で、輪郭付近の色味がおかしくなってますけど。
ところで、チョコレートに含まれるカフェインは鳥さんにとって猛毒なので与えてはいけないそうです。世帯主の皆さん、ご存知でしたか?
さらに、アイス部分に16x16の大きさのモザイクをかけます。

f:id:NU_Pan:20151221230507p:plain
(アカン)
さて、こいつに、今回紹介した3つの手法を適用すると…

f:id:NU_Pan:20151221230702p:plain
なんだかモザイクの存在感が薄くなったような気がしません??????
特に縮小版だといい感じの結果に見えますね!

全体モザイク画像のブレンディングは、そこそこ効果が有るように思いますが、輪郭線状に違和感が出てしまうという問題があります。ブロック内の平均をとるので、極端な色がある程度まざると、その色に引っ張られてしまうんですね。
チェスボードは結構効果的で、これをかけると、途端にモザイクが認識しづらくなります。本来の画像のディティールをほぼ失わずにこれだけの効果が出るのはすごい。
ガウス平滑化はこれ意味あるんですかね? もうちょっと方法を考えないとあってもなくても変わらない処理かも。むしろ、チェスボードの効果を打ち消してしまっている気もする。

ちょっとパラメータをいじってみて経験的にわかったこととしては

  • 全体モザイク画像のブロックサイズは、元々かかっているモザイクと同じ大きさにすれば良い
  • チェスボードパターンのブロックサイズは、元々かかっているモザイクの半分のサイズにすれば良い

ってところでしょうか。

作ったプログラム

githubに上げました(Nu-Pan/censor_reduction · GitHub)
実装はOpenCV + C++です。

まとめ

モザイクをごまかす画像処理を考えて実装、実験した。
モザイクとは無関係な領域の劣化と引き換えにそれなりの効果は見られた。

今後の課題

  • 各パラメータの最適値は経験的に求められそう
  • 元からかかっているモザイクのサイズを自動推定したい
    • ブロックサイズを自動決定できる
  • 画像処理に若干時間がかかっていてインタラクティブなパラメータ調整に難がある
    • SSE使って高速化するだけでだいぶ改善しそう
  • GUIがボロボロ
  • チェスボードはブレンディング(乗算)ではなく変化量を指定(加減算)するべきかも

翌日の記事

じょんどろ(じょんどろ (@_Nnwww) | Twitter)さんです。OCです。

そのほか効果がありそうなこと

思いついたけど、実装してないこと。

OpenCVに実装されている超解像処理

原論文をみていないのでなんとも言えないが、もしかしたら効果あるかも?

平面フィッティングでモザイク処理

何らかのモデルをブロックに当てはめて、それで輝度値を計算する。

モザイク領域の自動検出

近傍が同色だらけで注目ピクセルがその色ならモザイク領域
ウィンドウサイズ、同色判定の色距離しきい値、同色数のしきい値は手動調整
スーパーピクセル使えそう?
幾何学AICで繰り返しパターン検出?

人工的なざらつき付加

DFT使って高周波数成分を自動生成?
PCAとか使える?