職人じゃないけどAAがしたい!

作ったもの*1

https://image2aa.genya0407.net/

AA(アスキーアート)とは

f:id:threetea0407:20210801133652p:plain

AA(アスキーアート)というのは、上の画像のように文字で書かれた絵のことです。一般には「AA職人」が職人芸で作ります。

元々は画像が貼れない2chで絵を表現するための手段だったと思われますが、近年はフォントの違いによって絵が崩れるのを防ぐためにAAの画像を貼るまとめブログなどもあるようです。

アスキーアートを自動で生成したい!

f:id:threetea0407:20180203174748p:plain:w400

AA作成には特殊な技術が必要なので、一般人はAAを作れません。

僕だって好きなキャラクターのAAを作りたいのに...

AAを画像から生成できればいいのに...

それRustでできるよ

画像からAAを自動生成するWebアプリ

デモ

画像からAAを自動生成するWebアプリ *2

f:id:threetea0407:20180203194043g:plain

このWebアプリRust言語で作成されています💪

どうやって実現しているのか

以下の3段階の処理を行ないます。

  1. 線画を抽出する
  2. 画像を分割する
  3. 部分画像ごとに文字を割り当てる

1. 線画を抽出する

f:id:threetea0407:20180203180347p:plain

まずは線画を抽出します。

線画を抽出するには、以下の2段階の処理を行います。

  1. ソーベルフィルタをかける
  2. 2値化する

ソーベルフィルタ

↓こういう畳込みフィルタを掛けます。

f:id:threetea0407:20180203180738p:plain:w200

http://ipr20.cs.ehime-u.ac.jp/column/gazo_syori/chapter5.html より引用

これをすると「周囲との差が大きいピクセル」は値が大きくなり、「周囲との差が小さいピクセル」は値が小さくなります。

2値化

画像において「線」は「周囲との差が大きいピクセル」の集合です。 なので、ソーベルフィルタの結果に対して「ある値より大きいピクセルは白色、ある値より小さいピクセルは黒色」というように2値化すると、線画が生成されます。

2. 画像を分割する

f:id:threetea0407:20180203183433p:plain

図のように、線画を適当な大きさのブロックに分割します。

3. 文字を割り当てる

各ブロックに似た文字を割り当てることで、アスキーアートを得ることができます。 上図の例では「縦棒の画像」を「|」に割り当てています。

ここで問題になるのは各ブロックに似た文字とはなんぞや?ということです。

「似ている」とはどういうことか

画像と文字が「似ている」とはどういうことでしょうか?

いろいろな方法で「似ている度合い」を計算することはできるでしょうが、ここでは「直線の傾き」に着目します。 つまり、「画像の直線の傾き」と「文字の直線の傾き」を比較して、それらが近い時に「画像と文字が似ている」とします。

上の画像の例だと、「縦棒の直線の傾き」と「|の傾き」が近いため、「|」を割り当てるということです。

直線の傾きをどう求めるのか?

では、直線の傾きはどのように求めればよいのでしょうか?

これについてもいろいろな手法があるでしょうが、ここではハフ変換というのを使います。 ハフ変換を使うと、画像内に含まれる直線の傾きと、その直線の原点からの距離を求めることができます。

あとは、画像の直線の傾きと文字の直線の傾きを比較して、近いものを割り当てればアスキーアートが得られます。

完成 🙌

f:id:threetea0407:20180203185136p:plain

このように、

  1. 線画を抽出する
  2. 画像を分割する
  3. 部分画像ごとに文字を割り当てる

の3段階の処理を行なうことで、画像からアスキーアートを生成することができます。

*1:2021/07 ホスト先を変更しました

*2:2021/07 ホスト先を変更しました

*3:以前は web と cli を別レポジトリで管理していましたが、1つのレポジトリに統一しました