2017/04/09(日) [n年前の日記]
#1 [dxruby][ruby] ドット絵モドキを自動生成するRubyスクリプトを少し手直し
ドット絵モドキを自動生成するソレを Ruby + DXRuby で試しているところ。
_先日の実験 では、乱数でテキトーにドットを打っていくという安易なやり方でも、
結果はこんな感じに。前回は3倍表示してたけど、コレは原寸表示。(16x16 を Scale3x で3倍に拡大して生成。
意外とイケそうな…でもないかな…どうなんだ…ちと判断が難しい微妙な結果に。
ちなみに、8倍に拡大するとこんな感じに。
これはこれで味わい深い…のかな…どうなんだ…。
_先日の実験 では、乱数でテキトーにドットを打っていくという安易なやり方でも、
- 生成サイズを 8x8 〜 16x16ドットぐらいに小さくしておく。
- 輪郭と言うか、型と言うか、シルエットを大まかに決めておく。(今回はsinカーブで決めている)
- 境界線(黒い縁)をつける。
- 使う色数を少なくしておく。
結果はこんな感じに。前回は3倍表示してたけど、コレは原寸表示。(16x16 を Scale3x で3倍に拡大して生成。
意外とイケそうな…でもないかな…どうなんだ…ちと判断が難しい微妙な結果に。
ちなみに、8倍に拡大するとこんな感じに。
これはこれで味わい深い…のかな…どうなんだ…。
◎ ソースについて。 :
ソースは以下。tinypixelartgen_take3.rb と scalenx.rb の2つが必要。
_tinypixelartgen_take3.rb
_scalenx.rb
Ruby + DXRuby がインストールされてる環境で、ruby tinypixelartgen_take3.rb を実行すると生成される。スペースキーを押せば次々に生成し直し。
_tinypixelartgen_take3.rb
_scalenx.rb
Ruby + DXRuby がインストールされてる環境で、ruby tinypixelartgen_take3.rb を実行すると生成される。スペースキーを押せば次々に生成し直し。
◎ ライセンス面での問題。 :
惜しむらくは、Scale2x、Scale3x がGPLなので、Scale2x、Scale3x を利用してるこのドット絵自動生成スクリプトも GPL になるあたりが厳しいなと。いわゆるGPL汚染。
このスクリプトを何かに組み込んで利用したいと思っても、おそらくはそのアプリ全体までGPLで配布しないといけないのだろうと…。MIT License や CC0 / Public Domain に比べると、GPLは不便と言うか不自由だなと。
ん? 待てよ? 自分は _Scale2xのアルゴリズム解説ページ を参考にしてソースを書いたけど、 _Scale2x の exe のソース は一切見ないでソースを書いたわけで…。それでもこのスクリプトはGPLになるんだろうか?
いや、でも…。処理の肝心要の部分を解説ページ中から丸々コピペしてるのだから、コレはやっぱり GPL になるのかしらん。どうなんだろう。
まあ、ニアレストネイバー(Nearest neighbor)で拡大したほうがドットが強調されてドット絵らしさが増すのでは、という気もするので、いざとなれば Scale2x を使ってるあたりをゴッソリ削除してもいいんじゃないか、そうなれば自由に使えるやろ、と思ったりもしますが。
このスクリプトを何かに組み込んで利用したいと思っても、おそらくはそのアプリ全体までGPLで配布しないといけないのだろうと…。MIT License や CC0 / Public Domain に比べると、GPLは不便と言うか不自由だなと。
ん? 待てよ? 自分は _Scale2xのアルゴリズム解説ページ を参考にしてソースを書いたけど、 _Scale2x の exe のソース は一切見ないでソースを書いたわけで…。それでもこのスクリプトはGPLになるんだろうか?
いや、でも…。処理の肝心要の部分を解説ページ中から丸々コピペしてるのだから、コレはやっぱり GPL になるのかしらん。どうなんだろう。
まあ、ニアレストネイバー(Nearest neighbor)で拡大したほうがドットが強調されてドット絵らしさが増すのでは、という気もするので、いざとなれば Scale2x を使ってるあたりをゴッソリ削除してもいいんじゃないか、そうなれば自由に使えるやろ、と思ったりもしますが。
◎ 課題というか別の疑問。 :
「5x5ドットぐらいなら横方向3ドット分を作ってミラーするだけでもそれっぽくなるよ」てな方法があるのだけど。
_Space Invader Generator | The 8Bit Pimps Pixel Mine
たしか、GitHubのアイコンも同様の手法で生成されてたと思ったけど。
_Identicons!
それらの各1ドットに、事前に用意した8x8ドットのパターンをランダムに置いていったらどうなるかなと疑問が。例えば以下のようなパターンを使って…。
_mieki256's diary - DXRubyでキャラグラエディタを作ってみた
どうなるんでしょうね。
_Space Invader Generator | The 8Bit Pimps Pixel Mine
たしか、GitHubのアイコンも同様の手法で生成されてたと思ったけど。
_Identicons!
それらの各1ドットに、事前に用意した8x8ドットのパターンをランダムに置いていったらどうなるかなと疑問が。例えば以下のようなパターンを使って…。
_mieki256's diary - DXRubyでキャラグラエディタを作ってみた
どうなるんでしょうね。
[ ツッコむ ]
#2 [ruby] 配列の初期化って時間がかかるのだな
昨日書いた Scale2x の処理を行う Ruby スクリプトを、もうちょっと最適化できないものかと弄っていたのだけど。
ループ内をアレコレ弄って「あまり速くならねえな」とガッカリした直後、ふと、配列の初期化はしなくてもいいんじゃないかと気が付いて。配列の確保だけするようにしてみたら処理時間が二桁減って愕然。 *1
配列の初期化って結構処理時間を食うのだな…。いやまあ、メモリを確保して中身を書き換えていくわけだから当然だろうけど。にしても、まさか条件分岐が山ほど入ってるループ処理部分より配列の初期化で時間を食ってたとは…。
ループ内をアレコレ弄って「あまり速くならねえな」とガッカリした直後、ふと、配列の初期化はしなくてもいいんじゃないかと気が付いて。配列の確保だけするようにしてみたら処理時間が二桁減って愕然。 *1
配列の初期化って結構処理時間を食うのだな…。いやまあ、メモリを確保して中身を書き換えていくわけだから当然だろうけど。にしても、まさか条件分岐が山ほど入ってるループ処理部分より配列の初期化で時間を食ってたとは…。
◎ 測ってみた。 :
こんな感じで。環境は Windows10 x64 + Ruby 2.2.6-p396 mingw32版。
結果。
配列の中身をゼロクリアするとやっぱり遅くなるようで…。多次元配列じゃなく一次元配列にしてゼロクリアしたら速くならないか、と思ったけど甘かった。でもないか。いや、しかし、多次元配列の確保より、一次元配列でゼロクリアするほうが遅いんだよな…。
ちなみに、Ruby 2.2 ではなく Ruby 2.3 でも試してみたけど、さほど違いは無く。ていうかむしろ微妙に遅くなったり。まあ、誤差かもしれないけど。
# Array.new のベンチマーク require 'benchmark' w, h = 512, 256 Benchmark.bm(7) do |x| # 最初にやってたソレ x.report("[][][]") do a = Array.new(h).map { Array.new(w).map { Array.new(4, 0) } } end # 書き方を変えてみた x.report("[][][]B") do a = Array.new(h) { Array.new(w) { Array.new(4, 0) } } end # ループを馬鹿みたいに回してみた x.report("loop") do a = [] h.times do b = [] w.times do b << [0, 0, 0, 0] end a << b end end # 初期化を省いた x.report("[][]") do a = Array.new(h).map { Array.new(w) } end # 一次元配列にしてみた x.report("[]") do a = Array.new(w * h * 4, 0) end end
結果。
user system total real [][][] 0.047000 0.000000 0.047000 ( 0.049730) [][][]B 0.047000 0.000000 0.047000 ( 0.041508) loop 0.031000 0.000000 0.031000 ( 0.032914) [][] 0.000000 0.000000 0.000000 ( 0.000188) [] 0.000000 0.000000 0.000000 ( 0.000549)
配列の中身をゼロクリアするとやっぱり遅くなるようで…。多次元配列じゃなく一次元配列にしてゼロクリアしたら速くならないか、と思ったけど甘かった。でもないか。いや、しかし、多次元配列の確保より、一次元配列でゼロクリアするほうが遅いんだよな…。
ちなみに、Ruby 2.2 ではなく Ruby 2.3 でも試してみたけど、さほど違いは無く。ていうかむしろ微妙に遅くなったり。まあ、誤差かもしれないけど。
*1: もっとも、渡された配列の中身をそのまま使う形になった ―― ポインタだけを書き換えてる形になったようなものだから、元の配列の内容を弄られるとおかしなことになるけれど、それは元々そうなってたから今更だし。
[ ツッコむ ]
#3 [ruby][dxruby] RGBとHLS(HSL)を変換するRubyスクリプトを書いた
グラデ塗りを試す際に必要になりそうだったので、RGBと
_HLS(HSL)
を変換するRubyスクリプトを書いた。
HLSてのは…。、Hue(色相)、Lightness(輝度)、Saturation(彩度)で色を表す例のヤツ、という説明でいいのだろうか。お絵かきソフトでえてして用意されてたりするアレ。とはちょっと違うか。アレは _HSV か…。
とりあえず、変換処理のソースは以下。
_tinycolorsys.rb
_RGBとHSLの相互変換ツールと変換計算式 - PEKO STEP の解説を参考にして書きました。ありがたや。
使用例。
DXRuby を使って、マウスのx/y座標やカーソルキーの上下でHLSの値を変えて、背景色を変更してる。
require_relative 'tinycolorsys' を呼んで、include TinyColorSys しておくと、hls_to_rgb() と rgb_to_hls() が使えるようになる。
_test_colorsys.rb
HLSてのは…。、Hue(色相)、Lightness(輝度)、Saturation(彩度)で色を表す例のヤツ、という説明でいいのだろうか。お絵かきソフトでえてして用意されてたりするアレ。とはちょっと違うか。アレは _HSV か…。
とりあえず、変換処理のソースは以下。
_tinycolorsys.rb
_RGBとHSLの相互変換ツールと変換計算式 - PEKO STEP の解説を参考にして書きました。ありがたや。
使用例。
DXRuby を使って、マウスのx/y座標やカーソルキーの上下でHLSの値を変えて、背景色を変更してる。
require_relative 'tinycolorsys' を呼んで、include TinyColorSys しておくと、hls_to_rgb() と rgb_to_hls() が使えるようになる。
_test_colorsys.rb
# tinycolorsys.rb の動作テスト require 'dxruby' require_relative 'tinycolorsys' include TinyColorSys fnt = Font.new(28) v2 = 0.5 set_hls = true Window.loop do break if Input.keyPush?(K_ESCAPE) set_hls = !set_hls if Input.mousePush?(M_LBUTTON) v0 = Input.mousePosX.to_f / (Window.width - 1) v1 = Input.mousePosY.to_f / (Window.height - 1) v2 += (Input.keyDown?(K_UP))? (1.0 / 255.0) : 0 v2 -= (Input.keyDown?(K_DOWN))? (1.0 / 255.0) : 0 v0 = [[v0, 1.0].min, 0.0].max v1 = [[v1, 1.0].min, 0.0].max v2 = [[v2, 1.0].min, 0.0].max if set_hls h = v0 l = v1 s = v2 r, g, b = hls_to_rgb(h, l, s) h = (h * 360).to_i l = (l * 100).to_i s = (s * 100).to_i else r = (v0 * 255).to_i g = (v1 * 255).to_i b = (v2 * 255).to_i h, l, s = rgb_to_hls(r, g, b) h = (360 * h).to_i l = (100 * l).to_i s = (100 * s).to_i end Window.bgcolor = [r, g, b] col = (l < 50)? C_WHITE : C_BLACK msg = (set_hls)? "use HLS" : "use RGB" Window.drawFont(4, 4, msg, fnt, :color => col) Window.drawFont(4, 40, "RGB=#{r}, #{g}, #{b}", fnt, :color => col) Window.drawFont(4, 80, "HLS=#{h}, #{l}, #{s}", fnt, :color => col) Window.drawFont(4, 120, "(mouse x/y , Up/Down key)", fnt, :color => col) end
◎ 既にgemがあった。 :
上記のスクリプトを書いた後で、ふと気になってググってみたら、既にそういう gem があった…。自分で書く必要は無かった…。
_color | RubyGems.org | your community gem host
_halostatue/color: Color tools for Ruby.
gem install color でインストールできる。
以下は、前述のソレを color を使って書き直した例。
ホント、最初からコレを使えばよかった…。
_color | RubyGems.org | your community gem host
_halostatue/color: Color tools for Ruby.
gem install color でインストールできる。
以下は、前述のソレを color を使って書き直した例。
# gem color の動作テスト require 'dxruby' require 'color' fnt = Font.new(28) v2 = 0.5 set_hls = true Window.loop do break if Input.keyPush?(K_ESCAPE) set_hls = !set_hls if Input.mousePush?(M_LBUTTON) v0 = Input.mousePosX.to_f / (Window.width - 1) v1 = Input.mousePosY.to_f / (Window.height - 1) v2 += (Input.keyDown?(K_UP))? (1.0 / 255.0) : 0 v2 -= (Input.keyDown?(K_DOWN))? (1.0 / 255.0) : 0 v0 = [[v0, 1.0].min, 0.0].max v1 = [[v1, 1.0].min, 0.0].max v2 = [[v2, 1.0].min, 0.0].max if set_hls h = v0 * 360.0 l = v1 * 100.0 s = v2 * 100.0 rgb = Color::HSL.new(h, s, l).to_rgb r = rgb.red g = rgb.green b = rgb.blue else r = (v0 * 255).to_i g = (v1 * 255).to_i b = (v2 * 255).to_i hsl = Color::RGB.new(r, g, b).to_hsl h = hsl.hue l = hsl.luminosity s = hsl.saturation end r = r.to_i g = g.to_i b = b.to_i h = h.to_i l = l.to_i s = s.to_i Window.bgcolor = [r, g, b] col = (l < 50)? C_WHITE : C_BLACK msg = (set_hls)? "use HLS" : "use RGB" Window.drawFont(4, 4, msg, fnt, :color => col) Window.drawFont(4, 40, "RGB=#{r}, #{g}, #{b}", fnt, :color => col) Window.drawFont(4, 80, "HLS=#{h}, #{l}, #{s}", fnt, :color => col) Window.drawFont(4, 120, "(mouse x/y , Up/Down key)", fnt, :color => col) end
- Color::HSL.new(hue, saturation, luminosity) で渡す値は、hue が 0〜360、saturation と luminosity が 0〜100。
- Color::RGB.new(red, green, blue) で渡す値は、0〜255。
- HSL.to_rgb で RGB になるし、RGB.to_hsl で HSL になる。
- RGB.red、RGB.green、RGB.blue で取り出した値は、0〜255。
- HSL.hue、HSL.luminosity、HSL.saturation で取り出し値は、0〜360、0〜100、0〜100。
- HSL も RGB も、0.0〜1.0を与えて生成するメソッドがあるらしい。hsl = Color:HSL.from_fraction(0.5, 1.0, 0.5) みたいな書き方をすればいいのかな? たぶん。ちと自信無し。
ホント、最初からコレを使えばよかった…。
[ ツッコむ ]
#4 [gimp] G'MICプラグインがQtベースになるっぽい
G'MICプラグインという、500種類以上のフィルタが使える画像フィルタ集があるのですが。
*1
えてしてGIMPと組わせて使うことが多い、のかな。Kritaにも同梱されてたりしますが。
_G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing
_「G'MIC (GREYC's Magic Image Converter)」
最新版に更新してみようと公式サイトを開いて 2.0.0pre版をDLしようとしたら、gimp_gtk版とgimp_qt版の2つがあることに気が付いて。
_G'MIC - Google+ を眺めると…。どうやら 2.0.0版からはQtベースになるっぽい雰囲気。Qt、なんだか流行ってるなあ…。人気あるなあ…。
_G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing
_「G'MIC (GREYC's Magic Image Converter)」
最新版に更新してみようと公式サイトを開いて 2.0.0pre版をDLしようとしたら、gimp_gtk版とgimp_qt版の2つがあることに気が付いて。
_G'MIC - Google+ を眺めると…。どうやら 2.0.0版からはQtベースになるっぽい雰囲気。Qt、なんだか流行ってるなあ…。人気あるなあ…。
*1: 今現在、手元の環境で確認してみたら、526種類のフィルタが有効になってた…。
[ ツッコむ ]
以上、1 日分です。