2018年4月14日土曜日

ルービックキューブを解く(その1:画像認識して解く)

ルービックキューブの写真を撮って、色を認識して解く。
そんなことが出来ればと思い、格闘。

一面づつ写真を撮ってというやりかたは、面白くないので、3面づつまとめて。

最初はPHPでがりがり書いたが、画像認識に限界があり、C++とOpenCVの組み合わせに乗り替え。

まずは、写真の撮り方。画像処理をやりやすくするために、背景は100均で買ったフェルト生地を置いて撮影。
ルービックキューブの配置は、以下の面の位置で。
最終的には各面に番号を付け、行列(配列)に色を代入する。


左の写真
    左手前の面:Front面(中央が白)→0
    上の面:Up面(中央が赤)→1
    右手前の面:Right面(中央が緑)→5
右の写真
    左手前の面:Back面(中央が青)→2
    上の面:Down(中央がオレンジ)→3
    右手前の面:Left面(中央が黄)→4

写真をアップロードして、C++のプログラムで色の認識を行う。

【手順】
  1. 白黒画像に変換
    void cvCvtColor(const CvArr* src, CvArr* dst, int code)
  2. 確率的ハフ変換による線分の検出
    CvSeq* cvHoughLines2(CvArr* image, void* storage, int method, double rho, double theta, int threshold, double param1=0, double param2=0)
  3. 3点透視図として扱い消失点を求める
  4. 面に変換するためのホモグラフィ行列の推定
    void cvFindHomography(const CvMat* srcPoints, const CvMat* dstPoints, CvMat* H int method=0, double ransacReprojThreshold=3, CvMat* status=NULL)
  5. ホモグラフィ変換で各面(正方形)の画像を生成
    void cvWarpPerspective(const CvArr* src, CvArr* dst, const CvMat* mapMatrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0))
  6. 重み付け最小二乗法(Biweight推定法)で各キューブを推定
  7. HSV色空間に変換し、色相(H:Hue)を昇順ソート、彩度(S:Saturation、白)は降順ソートし、それぞれの色を推定
  8. 6x9の行列(面[6] × キューブ数[9])に色を設定
という感じで処理する。


各キューブの色行列ができたところで、3点透視図で再現。
  1. アフィン変換行列を算出
    CvMat* cvGetPerspectiveTransform(const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* mapMatrix)
  2. 各ポイントをアフィン変換し、画像を生成

とりあえず、画像認識で色を判別し、配列に代入。
さて、ルービックキューブを解きましょう。

まずは、回転の軸の設定

というような感じで各面を正面から見た時に、右回転を1に、左回転を-1に設定。
ルービックキューブ攻略サイトなどを参考にしながら、ステップごとにプログラミング。
メガハウスの6面完成攻略書を参考に。

【手順】
  1. クロスを作って上面(Up)を揃える(最小の手数で揃えられる面を選ぶ)
  2. 中段を揃える
  3. 裏(Down)のクロスを作る
  4. 裏(Down)を揃える
  5. コーナー、サブキューブを揃える
脳ミソがよじれる感じで計算し、回転方向を図示。
以下、抜粋。
クロスを作る。クロスの面は裏(Back)面なのでこの図では見えません。
以下が最終局面。 

で完成。
でも、120手が必要。う〜ん。


2017年5月7日日曜日

軍艦作る 〜ウォーターライン〜

もうかれこれ10年近く前に、日露戦争の連合旗艦の三笠を作った。
100均でケースを買い、紙粘土を塗装して海を表現。


その後、これまた7〜8年前にフジミ模型 の「大和 最後の出撃直前」をつくった。


こちらも板の上に紙粘土で海を再現。

さて、久しぶりに戦艦つくるぞってことで、空母に挑戦。
タミヤのアメリカ海軍の航空母艦 ヨークタウンを作る。ほぼ1日仕事。


完成。

 

さて、折角、軍艦が揃ってきたので、一気に並べる海を作ろうと思い。
大きなボードと紙粘土を用意して、ひたすら工作。


ボードに紙粘土たっぷり使って、造形をして、これまた100均で購入した青色のスプレーとアクリル塗料の青と白をふんだんに使って海を表現。
左からヨークタウン、三笠、大和を並べた。


いいんだけど、何かパンチが足りない。
ということで、クリアラッカーで光沢を出す。
すると。
いいんじゃないんすか。波荒れてますけど。


絵の具で海っぽい色としぶきを表現して、並べた。
ありえない組み合わせだけど、模型だからOK。



本日、天気晴朗ナレドモ、波タカシ」 (日露戦争 : 明治38年 東郷平八郎)
って感じですかね。
いやー、疲れた。


徒然なるままに今日も明日も。

2017年5月2日火曜日

飛び出す絵 描いた


暇だったので、飛び出す絵を描いてみた。
絵のモデルさんは、ロンドンに行ったときにお土産で買ったビッグベン。


さささっと描いて。



ん。いいんじゃないんすか。飛び出してる? ふん?

飛び出すっぽく、少し紙を切って。


うん。いい感じ。

色を塗ってみた。100均で水彩絵の具を買ってきて。


ぐっと良くなりました。
実物とツーショット。
ナイス。


ついでに、別の飛び出すやつも。


 今日の成果物を並べてみました。



いやぁ〜。
久しぶりに結構本気で絵描きました。


徒然なるままに、今日も明日も。

2017年4月9日日曜日

MacOSターミナルからX Window

あ、そうなのね。
って感じです。

MacOSのターミナルから以下の具合でX11 port forwardingオプション(オプション -Y)を有効にしてssh接続すると、Mac側でX関連のアプリが起動できる。

mac :~ user$ ssh -Y user@example.jp
user@example.jp's password:
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-66-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

0 個のパッケージがアップデート可能です。
0 個のアップデートはセキュリティアップデートです。

Last login: Sat Apr 1 12:36:53 2017 from 10.0.0.12
user$ xeyes &
user$ firefox &
user$ fgnome-terminal &
user$

Xアプリのコマンドをたたくと、自動的にMacOS側でXQuartzが起動し、Xアプリが動き始める。
ちなみにターミナルにはうにょうにょとエラーやらワーニングやらがでるが気にせず。



2017年4月8日土曜日

我が家のiPadたち 〜iPadでssh〜

あれよあれよという間にiPadが5台になった。




左から
  • 初代iPad(16 GB ブラック MB292J)
  • 初代iPad mini(32 GB ブラック A MD529J)
  • iPad Air(16 GB シルバー MD794J)
  • iPad Air 2(16 GB ゴールド MH1C2J)
  • iPad mini 4(32GB ゴールド MNY32J)

iPadから我が家のサーバーにssh接続するために、Bluetoothワイヤレスキーボードを購入。それもなるべく安いやつを探して。 エレコムのキーボードがAmazonで1,500円弱のお手頃価格。加えてクーポンも残っていたので、750円で買う。

     


さて、ではiPad mini 4でssh。その前にまずは、我が家のGateoneに接続を試す。


が、あ!?、スペースキーに反応しない!
コマンドを打つときにスペースキーが効かないとまったく使い物にならん!。う〜〜ん。いかん。

ということで、iPad用のsshクライアントをAppStoreで。
日本語入力も必要だが、現在対応しているアプリは、「Prompt 2 - SSH クライアント・コンソール・ターミナル」のみらしく、価格が1800円。キーボードより高い!
ということで、一旦日本語入力はあきらめ「Termius - SSH Shell / Console / Terminal」をダウンロード。


ワイヤレスキーボードTK-FBP052WHのモードを iOSに切り替える。[Fn]キーと[Mode]キーを押すと切り替えができる。
Termiusを起動し、Hostsを追加。


Aliasに適当な名前を付け、UserID、Hostname、Passwordを登録。あとは、Saveして追加したホストをタップすると、RSA Keyが表示されるので、「Continue」をタップするとログイン完了。

   

背景色や文字色も変えられる。


日本語入力ができないので、サーバーにemacs導入。
emacs24のテキスト版(nox)とEmacs-lispファイルをインストールし、Google日本語入力のMozcをインストール。

user$ sudo apt-get install emacs24-nox emacs24-el
user$ sudo apt-get install emacs-mozc

次にinit.el を編集。

user$ cat .emacs.d/init.el
(require 'mozc)
(set-language-environment "Japanese")
(setq default-input-method "japanese-mozc")
(prefer-coding-system 'utf-8)

とりあえず、ファイル編集の際の日本語入力はできるようになった。



参考:http://qiita.com/HirofumiYashima/items/a0e4011a5a32d61f124b


徒然なるままに今日も明日も。

2017年3月18日土曜日

sshでVPN。やってみる。


我が家のubuntuサーバでVPN(Virtual Private Network)を試みることに。
ssh(Secure Shell)のトンネリング機能を利用したVPNの備忘録。


(1) sshの準備

sshのトンネリングでは、デバイスの設定などroot権限が必要なこととVPNを行うためのトンネリング設定をconfig ファイル(/etc/ssh/sshd_conf)に書く必要がある。
PermitRootLoginとPermitTunnelを以下に。PermitRootLoginのforced-commands-onlyってのはルートでログインはできるけど、コマンド一発叩いて終わりってものらしい。
PermitRootLogin forced-commands-only
# 次にPermitRootLogin。レイヤー2(TAP)のみを許可する場合は、
# PermitTunnel ethernet
# レイヤー3(TUN) のみを許可する場合は、
PermitTunnel point-to-point
# 両方のトンネリングを許可する場合は、
# PermitTunnel yes
今回はレイヤー3のpoint-to-pointoに設定↑。ここで、sshdの再起動
server$ service sshd reload 

(2) ssh:鍵の生成と配置

クライアント側で秘密鍵と公開鍵をssh-keygenコマンドで生成。
鍵の名前を「vpn」としてrootで実行。パスフレーズはなしで設定。
client$ ssh-keygen -f ~/.ssh/vpn
(略)
  Your identification has been saved in /root/.ssh/vpn.
  Your public key has been saved in /root/.ssh/vpn.pub.
秘密鍵「vpn」と公開鍵「vpn.pub」が生成される。

サーバーにこの公開鍵(vpn.pub)を配置する。
scpなどで、クライアント側のvpn.pubをサーバーに転送し、鍵認証設定ファイル(authorized_keys)に追記する。
server$ cat vpn.pub >> authorized_keys
server$ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDi0BlNgdq・・・
(略)
server$ chmod 600 authorized_keys
server$ rm -fv vpn.pub

(3) 仮想ネットワークデバイスのTUN/TAP

TAPはデバイスのシミュレートで、TUNはネットワーク層のシミュレートだって。レイヤーが違うとのこと。
ubuntuはいいんですが、私のメインマシンのMacOSXはどうなんでしょう。
よくわからんが、Mac App Storeに「tuntap」なるものがあったので、とりあえずインストール。
client$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
client$ brew install tuntap
pythonでtunを開いたり設定したりできるみたい。

That Handy Tap Interface on Mac OSX
#!/usr/bin/python
import os
while 1:
 try:
  file_path = '/dev/tap1'
  dev_file = os.open(file_path, os.O_RDWR)
  interface = 'tap1'
  while 1:
   pass
 except:
  print "tap interface is closing"
  exit()
  break
PythonでTUN/TAPを使う
#!/usr/bin/python
import os
import subprocess
tun = os.open('/dev/tun0', os.O_RDWR)
subprocess.check_call('sudo ifconfig tun0
 192.168.100.2 192.168.100.1
 netmask 255.255.255.0 up',
 shell=True)
while True:
 data = os.read(tun, 1500)
 print(data)
 os.write(tun, data)

(4) sshでこの仮想ネットワークデバイスを利用した接続設定

authorized_keysの先頭に、rootでログインしたときの設定やコマンドを登録。
特定のコマンドを実行する際には、
command="/bin/ls -l" ssh-rsa ・・・
今回はtunを使ったデバイス設定コマンド(ifconfig)と禁止事項の設定を書く。
仮想ネットワークデバイスのtun0にアドレスを設定。サーバーのアドレスを10.0.0.1にクライアント側を10.0.0.2に。
ifconfig tun0 10.0.0.1 pointopoint 10.0.0.2 # デバイス設定コマンド
no-X11-forwarding  # X11 フォワードを禁止
no-agent-forwarding # 認証エージェント転送の禁止
no-pty # 端末の割り当て禁止
これらをまとめてauthorized_keysの先頭に。ssh-rsa ・・・の直前に記載する。
server$ cat authorized_keys
no-X11-forwarding,no-agent-forwarding,no-pty,command="ifconfig tun0 10.0.0.1 pointopoint 10.0.0.2" ssh-rsa AAAAB3NzaC1yc2EAAAADAQ・・・
(略)
これでサーバー側のsshの設定は完了。

クライアント側のssh接続の際の設定ファイル(.ssh/config)にも、クライアント側のデバイス設定などを記載。
client$ cat config
Host server
  HostName server
  IdentityFile ~/.ssh/vpn
  Tunnel point-to-point
  TunnelDevice 0:0
  RequestTTY no
  PermitLocalCommand yes
  LocalCommand ifconfig tun0 inet 10.0.0.2 10.0.0.1
ssh接続の際に実行するコマンドをLocalCommandで設定。
クライアント側のtun0は当然のことながらサーバー設定の逆。(クライアント自身のアドレスを10.0.0.2にサーバート側を10.0.0.1に)

ほぼ、これで準備完了。

(5) いざ、接続

某プロバイダーに接続を変えて(一旦、外部に接続を変更)、クライアントからssh接続をrootで実行。ポートはxxxに変更。
-wオプションは、ローカルtun [:リモートtun ] クライアント側のtunデバイス番号とサーバ側のtunデバイス番号を使ったトンネリングの要求)、-vオプションでメッセージを表示。
client$ ssh -v -w0:0 server -p xxx
debug1: Reading configuration data /root/.ssh/config
debug1: /root/.ssh/config line 1: Applying options for server
debug1: Reading configuration data /etc/ssh_config
debug1: /etc/ssh_config line 20: Applying options for *
debug1: /etc/ssh_config line 102: Applying options for *
debug1: Connecting to server [aaa.bbb.ccc.ddd] port xxx.
debug1: Connection established.
(略)
debug1: sys_tun_open: /dev/tun0 mode 1 fd 5
debug1: channel 0: new [tun]
debug1: channel 1: new [client-session]
(略)
debug1: Remote: X11 forwarding disabled.
debug1: Remote: Agent forwarding disabled.
(略)
debug1: client_input_channel_req: channel 1 rtype exit-status reply 0
debug1: client_input_channel_req: channel 1 rtype eow@openssh.com reply 0
debug1: channel 1: free: client-session, nchannels 2
って感じ。
サーバー側の状況。
server$ ifconfig tun0
tun0      Link encap:不明なネット  ハードウェアアドレス 00-00-00-00-00-・・・
          inetアドレス:10.0.0.1  P-t-P:10.0.0.2  マスク:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  メトリック:1
          RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:24 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:500 
          RXバイト:0 (0.0 B)  TXバイト:6820 (6.8 KB)
クライアント側。
client$ ifconfig tun0
tun0: flags=8851 mtu 1500
 inet 10.0.0.2 --> 10.0.0.1 netmask 0xff000000 
 open (pid 1289)
ちなみにpsコマンドでプロセスを確認すると、
client$ ps aux
USER PID  %CPU %MEM   VSZ    RSS  TT   STAT  STARTED   TIME    COMMAND
(略)
root 1289  0.0  0.1 2461144  2260 s001  S+    2:01PM   0:00.04 ssh -v -w0:0 server -p xxx
(略)
となっており、上記のifconfigで確認したクライアント側のtun0のプロセスid(pid 1289)とsshの接続コマンドのpidの一致がわかる。
で、クライアント側からpingで確認(10.0.0.2→10.0.0.1)。
client$ ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: icmp_seq=0 ttl=64 time=2.212 ms
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=3.751 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=2.054 ms
サーバーからも同様に(10.0.0.1→10.0.0.2)。
server$ ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=2.15 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=89.6 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=111 ms
とりあずpoint to pointは開通。
クライアントのルーティングテーブルを見ると、
client$ netstat -nr
Routing tables
Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            192.168.0.1        UGSc           19        0     en0
10.0.0.1           10.0.0.2           UH              1        6    tun0
127                127.0.0.1          UCS             0        0     lo0
127.0.0.1          127.0.0.1          UH              3     3512     lo0
169.254            link#4             UCS             0        0     en0
192.168.0          link#4             UCS             9        0     en0
このままではまだサーバー側のネットワーク(192.168.0.0/24)にアクセスできないので、クライアントのRouting tablesにゲートウェイとしてtun0を介したサーバーアドレスの10.0.0.1を追加。
client$ route add -net 192.168.0.0/24 10.0.0.1
client$ netstat -nr
(略)
Destination        Gateway            Flags        Refs      Use   Netif Expire
(略)
192.168.0          10.0.0.1           UGSc            0        0    tun0
pingをかけると、
client$ ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
いかん。まだ192.168.0.0側に通じてない。
サーバー側のtun0の様子をtcpdumpで見る。
client$ ping 192.168.0.1

server$ tcpdump -s0 -i tun0 -X
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
12:46:21.578871 IP 10.0.0.2 > 192.168.0.1: ICMP echo request, id 17924, seq 0, length 64
 0x0000:  4500 0054 de39 0000 4001 d1c4 0a00 0002  E..T.9..@.......
(略)
 0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
 0x0050:  3435 3637                                4567
12:46:22.531078 IP 10.0.0.2 > 192.168.0.1: ICMP echo request, id 17924, seq 1, length 64
 0x0000:  4500 0054 d813 0000 4001 d7ea 0a00 0002  E..T....@.......
(略)
 0x0020:  0006 ba82 0809 0a0b 0c0d 0e0f 1011 1213  ................
 0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
ルーティングは効いてつながってはいる。
ってことで、クライアントの.ssh/configのコマンドにルーティング設定も加える。
client$ cat config
Host server
  HostName server
  IdentityFile ~/.ssh/vpn
  Tunnel point-to-point
  TunnelDevice 0:0
  RequestTTY no
  PermitLocalCommand yes
  LocalCommand ifconfig tun0 inet 10.0.0.2 10.0.0.1;
 route add -net 192.168.0.0/24 10.0.0.1
ただ、サーバー側がまだ足りない。natして外に出られるようにする。
iptablesでルールの設定。「enp2s0」はサーバー側(192.168.0.0/24)のインターフェース。
tun0からは制限をかけず、ESTABLISHED,RELATEDは許可ってのも設定しておく。
server$ iptables -A FORWARD -i tun0 -o enp2s0 -s 10.0.0.0/24 -j ACCEPT
server$ iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
tun0(10.0.0.0/24)から出て行くパケットをサーバーのアドレスに書き換える。
server$ iptables -t nat -A POSTROUTING -o enp2s0 -s 10.0.0.0/24 -j MASQUERADE
iptablesの様子。
server$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  10.0.0.0/24          anywhere
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
(略)

server$ sudo iptables -L -t nat
(略)
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  10.0.0.0/24          anywhere
iptablesの保存。一応。
iptables-save
再度、ping。
client$ ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
64 bytes from 192.168.0.1: icmp_seq=0 ttl=63 time=724.364 ms
64 bytes from 192.168.0.1: icmp_seq=1 ttl=63 time=217.941 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=63 time=177.990 ms
いいんじゃないんっすか。
ちなみに別のMacBookで動いているWebサーバーにhttpかけてみると、
client$ telnet 192.168.0.49 80
Trying 192.168.0.49...
Connected to 192.168.0.49.
Escape character is '^]'.
GET /
<body><h1>
It works!</h1>
</body></html>Connection closed by foreign host.

OK。
いいんじゃないんっすか。
某プロバイダ経由はちょっとスピードは遅いけど、sshトンネルでvpnができた模様です。

以下のページを参考にしました。Special Thanks.


簡単に書いてみたけど、結構すったもんだ時間かかりました。勉強になった。。。


徒然なるままに今日も明日も。

2017年3月5日日曜日

無線ルーター親機交替

はやくも無線ルーターの親機が交替してしまいました。

長女の就職にともなってひとりぐらしになることに。
ネットはドコモ光を契約。

さて、無線ルーターが必要になりいろいろ考えた末、折角光回線使うんだし、我が家の親機、WHR-1166DHP3を使ってもらい、その代わり我が家の親機をグレードアップするかってことにしました。
細かく見ると、しぶいところで仕様が違うんですね。
WHR-1166DHP3の有線LANが「10M / 100Mbps(オートセンス)」に対して、WSR-2533DHP-CG」は、「LANポート:最大1000Mbps×4」だって。家庭内サーバーやNASもってると結構この違いは大きいかも。

ってことで、早速、 WSR-2533DHP-CGを購入。



ま、とにかくパワーアップ。ゴールドでしょう。やっぱり。

AirStation引越し機能 を使って、これまでのWHR-1166DHP3の設定を引き継ぎました。

でも、やっぱり途中で引っ掛かりました。
WSR-2533DHP-CGのAOSSボタン10秒間長押しして、これまで使っていた親機( WHR-1166DHP3)のAOSSボタンを押すとお引越しできると書いてあるのにできない。
ひょっとしてWPS機能ですか、ってんでWPS機能を「使用する」としたら、無事お引越し完了。

ポート変換など、必要な設定をして、無事移行完了しました。

WSR-2533DHP-CG(左)とj:comのBN-MUX BCW710J2(右)

インターネット側の速度はそれほど違いがなかったものの、ローカル側は、やっぱりギガ?

サーバー192.168.0.99へのスピードテスト

WHR-1166DHP3 WSR-2533DHP-CG
スピード(to 192.168.0.99) スピード(to 192.168.0.99)
1回目:10.379 [MB/sec] 1回目:20.672 [MB/sec]
2回目:10.744 [MB/sec] 2回目:20.258 [MB/sec]
3回目:10.635 [MB/sec] 3回目:20.689 [MB/sec]
→平均:88.800 [Mbps] 
  (10.586 [MB/sec])
→平均:172.300 [Mbps] 
  (20.540 [MB/sec])

約90Mbpsから約170Mbpsに向上。

グッバイWHR-1166DHP3。

徒然なるままに、今日も明日も。