午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

減色変換一覧表を使って処理時間を短縮してみた

昨日の手抜き法でパレット作成処理の時間は問題なくなったので次は

減色変換の処理時間を短縮
 
前の
単純減色(ポスタライズ?)試してみた、WPFC# ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15388558.html
この記事の時に使った変換一覧表方式を試した
 

f:id:gogowaten:20191212114831j:plain

元の画像がこれ
 
結果
イメージ 1
12秒かかっていたのを5秒にできた
変換1が今までので、変換2が一覧表方式
このときの条件は
画像の大きさが横2048、縦1536ピクセルという大きめサイズ
パレットの色数8
12.243/5.367≒2.28倍速くなった
 
今度は画像はそのままでパレットの色数を4色にしてみる

f:id:gogowaten:20191212120156p:plain

4色
イメージ 2
7.221秒/4.904秒≒1.47倍速くなった
パレットの色数が少ないと効果が薄くなる?
 
パレットの色数を20

f:id:gogowaten:20191212120216p:plain

イメージ 5
26.925秒/6.791秒=3.96倍速くなった
 
2048x1536の画像の場合
4色 7.221秒/4.904秒≒1.47倍速くなった
8色 12.243秒/5.367秒≒2.28倍速くなった
20色 26.925秒/6.791秒=3.96倍速くなった
 
 
今度は小さい画像
イメージ 6
4色
イメージ 7
0.114秒から0.266秒と逆に遅くなった
0.114/0.266≒0.429
 
イメージ 8
8色
イメージ 9
これも遅くなった
0.187/0.343≒0.545
 
 
イメージ 10
16色
イメージ 11
これも遅くなったけど差が縮まって
0.347/0.465≒0.746
192x256サイズの画像の場合
4色 0.114/0.266≒0.429
8色 0.187/0.343≒0.545
16色 0.347/0.465≒0.746
どの色数の場合も遅くなってしまったけど
色数がもう少し増えれば逆転しそう
 
 
サイズ1024x768の画像

f:id:gogowaten:20191212120344j:plain

f:id:gogowaten:20191212120404p:plain

4色
 
イメージ 13
この大きさだと4色でも一覧表方式が速い
 
 
一覧表は画像で使われている色全てに対する変換表で
画像のこの色はパレットのこの色に変換するっていう色と色が対になったもので
 
これにはDictionaryクラスを使った
イメージ 14
KeyとValueどちらもColorを指定すれば対になる
Keyに画像の色、Valueにパレットの色を入れておけば
Dictionaryに画像のある色を渡せば対応したパレットの色を返してくれる
 
これを作るには画像で使われている色をすべて取得する必要がある
画像の色をカウントする
普通の画像はRGB各8bitで各256階調は256*256*256=16777216色
この要素数のint型配列を作ってどの色がいくつあるのかカウントする
int[] colors = new int[16777216];
 
RGBをint型に変換する
RGB(0,0,0)の黒は0から
RGB(255,255,255)の白を16777215になるようにするには
R+(G*256)+(B*256*256)
 
例えば画像のあるピクセルがRGB(110,118,103)なら
110+118*256+103*256*256=6780526になる

f:id:gogowaten:20191212120419p:plain

これをさっきの配列の要素数(index)のところに1足す(カウントする)
colors[6780526]++;
イメージ 16
配列の6780526番目を見ようとしたけど999999以上は見れなかったw
でもこれでcolors[6780526]は1足したので0から1になるはず
これを画像のすべてのピクセルをカウントする
 
イメージ 17
ピクセルカウントしたところ
0のままのところはその色がなかったってことなので
これで画像に使われているすべての色が判別できる
 
変換一覧表作成
0以外の値があるindexは画像にある色のint型に変換したものなので、
これをRGBに戻して
パレットの色と比較して、
一番近いパレットの色を探して、
それぞれをDictionaryに入れていけば完成する
 
RGBに戻す
R = int % 256
G = int / 256 % 256
b = int / 256 / 256
小数点以下切り捨て(たぶん)
 
さっきの6780526だと
R=6780526 % 256=110
G=6780526 / 256 % 256=118.4
B=6780526 / 256 / 256=103.5
RGB(110,118,103)で元のRGBに戻る
 
パレットの色との距離は一番ラクなRGBのユークリッド距離で比較
色の距離は難しい、いくつか試したけどわからなかった ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15408771.html
 
 

f:id:gogowaten:20191212120513p:plain

最初の色0と対応するパレットの色がDictionary(converter)に入ったところ
色の表示は10進数じゃなくて16進数になっているからわかりづらい
#FF000000と#FF252D1Aが対になって入った
こんな感じで全部の色を処理して変換一覧表が完成する
 
イメージ 19
ぜんぶで290563色ぶんの対応表
290563対4だから右のValueはほとんど同じ色が並ぶことになる
イメージ 20
最後の方
 
 

f:id:gogowaten:20191212120536p:plain

変換一覧表を使っているところ
bitmapColorに今処理中のピクセルの色が入っている
これを変換一覧表のconverterに渡せば対応するパレットの色を返してくれるので
あとはそれに変換するだけ
 
 
 
変換一覧表を作るのに時間がかかるけど、作ってしまえば後の変換自体はかなり楽になるので、大きなサイズの画像やパレットの色数が増えても遅くなりにくいってことかなあ
あとは今回の一覧表はColorをColorの対応だけど、実際使いたいのはColorじゃなくてRGBそれぞれの値なんだよねえ、だから本当はbyte型配列とbyte型配列の対応表ができればもっと速くなるかも、RGB(1,2,3)だったら{1,2,3}を渡したらパレットの{2,8,9}を返すとか、いや、あんまりかわんないかな、そこまではいいや
 
コード全部はGitHub
 
アプリダウンロードはヤフーボックス
20180314_k平均法減色変換時間、変換一覧表1.1.zip(アルファ値が255以外の画像のときの処理を修正2018/03/20)
 
 
関連記事
2018/03/15 は1日後
 
Parallelクラスを使ってもっと速く減色 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15413665.html
 
 
2018/03/13は1日前
手抜きで時間を短縮、k平均法を使った減色パレットの作成 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15410540.html
2018/3/12は2日前
色の距離は難しい、いくつか試したけどわからなかった ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15408771.html
 
2018/3/4は10日前
k平均法で減色してみた、設定と結果と処理時間 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15397014.html
 
2018/2/26は16日前
単純減色(ポスタライズ?)試してみた、WPFC# ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15388558.html