メディアンカット法で減色してみた
ダウンロード先
理解できていないから間違っているかも
それでもいい結果が得られた
いつもの元画像を8色へ
いいねえ
ピクセル数が最大のCubeを優先分割
もう一つが
長辺が最大のCubeを優先分割のパレット
この写真画像だとあんまり変わんないけどねえ
これはこの前のk平均法での減色
どれもそんなに大きな差はないかなあ
パレットに選ばれる色
k平均法はランダム性があるので毎回違う色が選ばれるのが面白い
メディアンカット法は同じ色が選ばれるので安定性がある
処理速度
k平均法は遅い、設定によるけど上の小さな画像でも0.5秒から20秒もかかる
メディアンカット法は一瞬で終わる、それでも大きめ画像1024x768だとパレット作成に4秒、変換に4秒なので結構かかる、これは僕の書き方がイマイチなせいなところがあるけどメディアンカット法のほうがかなり速い
選ばれた色からの減色は前回同様に単純なRGBの距離を使っている
この画像の減色だとパレットに選ばれると良さそうな色は
緑、赤、白、黒、黄緑、茶
このあたりかなあ
6色に減色
ピクセル数優先は赤が無視されてイマイチの結果だけど
長辺優先はいいねえ
画像全体から見ると少ないけど目立つ赤系が選ばれるのは
ピクセル数優先だと
赤が選ばれたのは13色
ここまで増やさないと選ばれない
赤のピクセルは少ない画像なのでこうなる
長辺優先だと
4色の時点で早くも選ばれた、変換結果も悪くない
これが13色だと
赤系だけで3色も選ばれた
こういう画像だと長辺優先の設定のほうが元画像に近くなる
グラデーション画像
グレースケールはどちらも変わらず
ピクセル数の多い青空のグラデーションと
ピクセル数が少ないけど残ってほしい花の黄色
パレットの色選択処理と減色処理を分けたから
パレットの色を作って
パレットをそのまま画像だけ入れ替えて減色すると
全然違う色になる
トマト枯れたw
メディアンカット法の要は分割ってことみたい
2色なら分割を1回でおわり、■■■■を■■と■■
3色だと1回目は普通に分割なんだけど、2回目は1回目で分割したどちらの塊を分割するのかを選ぶ必要がある、その条件が今回のピクセル数や辺の長さで他にもいろいろあるみたい
画像の全ピクセルの色のRGB各3つの値を(Cube)直方体に当てはめて
このCubeを色数の分だけ分割していって、できあがったCubeの中の色からパレットの色を選ぶ
(Cube)直方体の頂点の一つを中心に決めて、そこから伸びる辺を色のRGB各3つの値
この中に全ピクセルの色を置いていって分割
分割前に色のないところを削る
青空の画像とかだと青以外の色は少ないから
こんな感じになったとして
分割する場所はRGBの中で一番長い辺の真ん中
なので青の真ん中
青の真ん中で分割してこれで2色
分割したらまたそれぞれの色のないところを削るここから3色にする時に
分割したどちらを分割するのか選ぶ条件が
Cubeに含まれるピクセル数が多い方
または一番長い辺がある方
とかになる
僕の場合はこれをC#のコードに書くのは難しくてできなかったので
立体じゃなくて線で試した
List<byte>の最大値と最小値と長さを持つMySplitクラス
青色がコンストラクタでbyte型配列からListを作って、最大値、最小値、長さを記録しているだけ
オレンジ色が自身を真ん中で分割する関数
分割それぞれのMySplitクラスを作ってそれをListにして返す
ところなんだけど
これはこのMySplitクラスの中に書かないで使う方に書いたほうがいいのかもと今思った
このクラスを使って分割のテストは
//1次元配列で分割ループテスト
byte[] iTest = new byte[20];
for (int i = 0; i < iTest.Length; ++i)
{
iTest[i] = (byte)i;
}
MySplit mySplit = new MySplit(iTest);
List<MySplit> listSplit = new List<MySplit>() { new MySplit(iTest) };
listSplit = SplitLoopTest(5, listSplit);//分割数指定で分割
0から19までの20個の数値を5分割
分割前は長さ(length)20で、0から19までの一塊これを
これに渡して分割
リストの要素数が多い方を優先して分割していく
listSplit ┗(0)MySplit、ここに20個入っている最初は塊1つしかないからこれを分割→152行目SplitHalf
549行目、真ん中で分割するので閾値になる真ん中の数値取得は
(最小値+最大値)/2=(0+19)/2=9.5
550行目、入れ物を2つ用意、lowとhighこれに分けていく分けた先の最小値、最大値も仕分けの際に記録する、lowMaxとhighMin
仕分けが終わったところ
真ん中の値9.5で分割されて10個づつに分けられた
それぞれを使ってMySplitを作成、570,571行目
して返す
152行目
返ってきたMySplit2つをlistSplitにAddRangeで追加されたところ
最初の塊に2つ足されたので3つになった
listSplit ┣[0]MySplit、最初の塊 ┣[1]MySplit、分割されて返ってきた塊 ┗[2]MySplit、分割されて返ってきた塊
153行目、最初の塊はもういらないので除去
除去したところ
0から9までの塊と10から19までの塊の2つに分割された状態
2色ならここで終了
次のループからはどちらの塊を分割するのかになる
大きい方や長い方を分割するけど
今回は長さ、長い方を分割
長さ(length)を見るとどちらも10
同じ場合は早い者勝ちにしてあるから0番
0~9が入っている方を分割
仕分け終了したところ
0~4と5~9に仕分けられた
分割された2つが返ってきてlistSplitに追加されたところ
listSplit ┣[0]MySplit、1回目の分割 ┣[1]MySplit、1回目の分割 ┣[2]MySplit、分割されて返ってきた塊 ┗[3]MySplit、分割されて返ってきた塊0番は分割されて2番、3番に追加されてもういらないので除去
次の分割対象はLengthが10の0番
これを指定された5分割まで繰り返した結果
これだとわかりにくいので
5,6,7,8,9,
10,11,12,13,14,
15,16,17,18,19,
0,1,
2,3,4,
こうなった
個数だと5,5,5,2,3
いいねえ、できた
0~255までのランダムな数値10000個を5分割
10000個の値
byte[] iTest = new byte[10000];
Random random = new Random();
random.NextBytes(iTest);
byte型の配列を渡すと中にbyte型のランダム値を入れて返してくれる
forとかで回さなくていいので楽ちん
ランダム値10000個を5分割結果
2557個: 最小値=0 最大値=63
2437個: 最小値=128 最大値=191
2432個: 最小値=192 最大値=255
1346個: 最小値=64 最大値=95
1228個: 最小値=96 最大値=127
ランダム値20個を5分割、1回目
2個: 最小値=201 最大値=249
5個: 最小値=142 最大値=167
5個: 最小値=175 最大値=195
6個: 最小値=15 最大値=57
2個: 最小値=63 最大値=105
ランダム値20個を5分割、2回目
4個: 最小値=2 最大値=42
7個: 最小値=149 最大値=187
2個: 最小値=203 最大値=247
3個: 最小値=63 最大値=87
4個: 最小値=88 最大値=112
ランダム値5個を5分割
1個: 最小値=186 最大値=186
1個: 最小値=13 最大値=13
1個: 最小値=62 最大値=62
1個: 最小値=133 最大値=133
1個: 最小値=136 最大値=136
ランダム値5個を7分割
1個: 最小値=177 最大値=177
1個: 最小値=225 最大値=225
1個: 最小値=249 最大値=249
0個: 最小値=185 最大値=-2147483648
1個: 最小値=185 最大値=185
0個: 最小値=111 最大値=-2147483648
1個: 最小値=111 最大値=111
個数以上に分割しようとするとエラーにはならないけど最大値は初期値に設定しているintの最小値
こんな感じで1次元配列ではできた
目的の直方体もほとんど同じなんだけど、最初は書けなかったんだよねえ
コード全部貼り付けたら文字数上限超えたみたいで投稿エラーなので一部だけ
さっきのMySplitクラスをRGB用に書き換えたCubeクラス
MySplitクラスと比べてプロパティが増えて、分割のところでRGBどの辺が長いのかの判定が増えただけかな
166行目と181行目、SplitCubeByLongSideとSplitCubeByColorsCountに分割数とCubeのリストを渡して分割している
どの塊(Cube)を分割するかの判定
選んだCubeを渡して分割されたのが返ってきたらリストに追加して元のCubeを除去
ってのは1次元配列のときと全く同じ
コード全部
↑に実行(.exe)ファイルも置いたんだけど、ダウンロードするとウイルスを検出しましたって警告が出る、そうなるとDebugで使っている実行ファイルもウイルス警告が出て検疫されてしまう、その後にDebug実行して作成されたファイルは警告が出ない
アップロードしてダウンロードするとまたウイルス警告が出る
試しにzipで圧縮した実行ファイルをアップロードしてダウンロードして展開したら今度はウイルス警告は出ない
ってことは実行ファイルそのものをダウンロードすると、ウイルスの有無にかかわらず問答無用でウイルス判定されているみたい
もう少し詳しく記事にしてみた
作ったアプリの実行ファイルがウイルスだと言われるw ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15400739.html
参照したところ
減色アルゴリズム[量子化/メディアンカット/k平均法]C#がないんだよなあ、JavaとScala、Scalaってのは初めて聞いたプログラム言語、どちらもほとんど読めなかったけど、Cube用にクラスを作ってるんだなあって雰囲気だけ真似してみた
https://www.petitmonte.com/math_algorithm/subtractive_color.html
メディアンカット法による画像の減色|スパイシー技術メモ
https://www.spicysoft.com/blog/spicy_tech/001253.html
ゆるゆるプログラミング 減色処理(メディアンカット)
http://talavax.com/mediancut.html
24bit → 8bit 減色: koujinz blog
http://koujinz.cocolog-nifty.com/blog/2009/04/24bit-8bit-a879.html
今改めてリンク先を読んでみたら、分割したCubeから色を選択する方法もCubeの中心の色や外側の頂点、Cube同士が隣接しているところの頂点とかいろいろある
関連記事
2日前
k平均法で減色してみた、設定と結果と処理時間 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
次の記事は3日後
指定色で減色+誤差拡散、減色結果を他のアプリと比較してみた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15405037.html
2018/03/21は15日後
Cubeから色の選び方、メディアンカットで減色パレット ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15421887.html