スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


にほんブログ村 その他趣味ブログ LEGO・ブロックへ

お絵かきロボ - プログラミング編 (3/4)

前のyoutubeに対抗心をもやして、モナリザを書くことにしました。これが運の尽きだったのかもしれません。

モナリザの絵をLEGOに書かせるためには、絵の一画一画をあまり短い直線ではなく、できれば1cmぐらいで近似したいところです。結局以下のステップを踏みました。
1. JTrimでグレースケール変換してから2階調化(2値化とも言います)。顔の部分だけ切り出す。
2. Potraceでベクトルデータ化。
3. Inkscapeで「パスの簡略化」および「セグメントの直線化」を適度に適用した後に、多角形で人力トレース。

最終産物は輪郭の直線を含むsvgファイルになります。分かりやすさのために、塗りつぶした後のpngは以下になります。
モナリザ - 塗りつぶし後
レゴの腕にとって遠すぎる部分を削った後の、塗りつぶす前の輪郭のsvgファイルはここにアップしておきます(FC2のルールのため、拡張子はxmlに変更しました)。物好きな方いましたら自由に使ってください。うまく輪郭が描けたら、次はペンで輪郭を少しずらしながらたどっていって顔の重要パーツのみは塗りつぶす作戦です。

次は、svgファイルの座標からRobotCに渡すxy座標への変換です。まずは輪郭のsvgファイルの描画の部分だけが抜き出したものがこれで、次の拙作rubyプログラムで変換しました。
#!/usr/bin/env ruby 

ZOOM = 250
X_SHIFT = -180
Y_SHIFT = +180
R1 = 106.4927
R2 = 131.2091

out_a = []
rtuv_a = []

x, y = 0, 0
rel_ready = false
pen_ready = false

svg_a = open("mona_1366x706.txt"){ |fin| fin.gets }.chomp.split
svg_a.each do |str|
   case str
   when "m"
      out_a << "{0,-100}"
      rel_ready = true
      pen_ready = true
   when "M"
      out_a << "{0,-100}"
      rel_ready = false
      pen_ready = true
   when "0,0"
   when "l"
      rel_ready = true
   else
      case rel_ready
      when true
         mx, my = str.split(',').map{ |a| a.to_f } 
         x += mx
         y += my
      when false
         mx, my = str.split(',').map{ |a| a.to_f } 
         x = mx
         y = my
      end
      px = x/1366*ZOOM + X_SHIFT
      py = -y/706*ZOOM*706.0/1366 + Y_SHIFT
      
      r = Math.sqrt(px*px+py*py)
      t = Math.atan2(py, px)
      t += Math::PI if t < 0
      v = Math.acos((r*r-R1*R1-R2*R2)/(2*R1*R2))
      degB = Math.atan(R2*Math.sin(v)/(R1+R2*Math.cos(v)))
      u = (degB < 0) ? t-(degB+Math.PI) : t-degB
      rtuv_a << [r,t,u,v]
      
      out_a << "{%.4f,%.4f}" % [px, py]
      out_a << "{0,-10}" if pen_ready
      pen_ready = false
   end
end

out_a << "{0,-100}"

r_a, t_a, u_a, v_a = rtuv_a.transpose
puts "total number of points: #{out_a.size}" 
puts "R1+R2: #{R1+R2}"
puts "(r) max: %.3f min: %.3f" % [r_a.max, r_a.min]
puts "(t) max: %.3f min: %.3f" % [t_a.max, t_a.min].map{ |rad| rad*180/Math::PI }
puts "(u) max: %.3f min: %.3f" % [u_a.max, u_a.min].map{ |rad| rad*180/Math::PI }
puts "(v) max: %.3f min: %.3f" % [v_a.max, v_a.min].map{ |rad| rad*180/Math::PI }
puts 
puts "  float xy_a[][2] = {" + out_a.join(",") + "};"

最終結果はこちらになります。結果の total number of pointsの数字と、C言語の配列の部分は次のRobotCのプログラムで使います。また、rの最大値がR1+R2以下かどうか、tが[0,180]の範囲か、uが[20,180]ぐらいの範囲か、vが[0,180]の範囲かをチェックします。駄目なら一番上の方の定数の部分をチョコチョコいじって修正します。なるべく顔の部分が大きくなるようにしないと1mm程度の直線を書くはめになり、それは厳しいためです。なお、確認のため、結果の座標部分だけを取り出してplotすると以下になります。
xy座標をplotしたもの
塗りつぶしていないと別人ですね…。
スポンサーサイト


にほんブログ村 その他趣味ブログ LEGO・ブロックへ

コメントの投稿

非公開コメント

リンク
フリーエリア
プロフィール

tsukuba.lego

Author:tsukuba.lego
●主な登場人物
koba : 会長. RCX, WeDo, NXT1.0, NXT2.0を持つ.
matk : 副会長. 2010年夏にNXT2.0を購入, 20年来のレゴ熱復活.
●会員募集中です!小学生から歓迎. 近日月1ぐらいで集まる予定.
mail:tsukuba.lego@gmail.com
YouTube (tsukubalego)
Twitter(tsukubalego)

カテゴリ
最新記事
最新コメント
月別アーカイブ
検索フォーム
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

QRコード
QR
最新トラックバック
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。