セカンドディスプレイのタッチを有効に働かせる方法

先日、液晶テレビを買ったので、家族用のタッチ液晶 LG-23ET83 が不要になりました。液晶テレビに PC がつなげられるので、(ちょっと字は滲みますが)ブラウザも快適に動いています。そうそう、Mac mini をつなげて字の滲みを比較する予定なのですが、まだやっていません。

さて、余ったタッチ液晶を仕事用のディスプレイにしようと思って、3面にしました。

image

メインではなくて、セカンドディスプレイにしてあるのは、タッチパネルためか映り込みが激しいんですよね、このディスプレイ。映像を映しているときにはいいのですが、面と向かってプログラミングをすると自分の顔を見ながら仕事する、ってことになってちょっと変です。なので、通常は、左のディスプレイで作業をして、真ん中をタッチにしようと考えたわけです。

■メインディスプレイにタッチが移動する?

この順番でつなげると、何故か、タッチ用の2番のディスプレイを触っているにも関わらず、1番目の液晶のマウスカーソルが動きます。どうやら、タッチ液晶の反応を別のディスプレイ(メインディスプレイ)に送っているらしい現象なんですよね。

仕方がないので、2番目のタッチ液晶の「これをメインディスプレイにする」にして作業をしていました。何故か、メインディスプレイに設定すると、タッチ部分と液晶表示は同期するのです。これでもまあいいのですが、タスクバーの時計が表示されているところが、メインのタスクバーだけなので、ちょっと変な感じなんですよ。あと、デスクトップにアイコンを作るときはメインディスプレイに作成されるので、いちいち2番目のディスプレイ(タッチ液晶)に探しに行かないといけません。

非常に面倒だった…のですが、解決策がありました。

■タブレットPC設定で、タッチ液晶を設定する

コントロールパネルで「タッチ」を検索して、「タブレットPC設定」をクリックします。

image

構成にある「ペンとタッチディスプレイを構成します」の「セットアップ」ボタンをクリックすると、どれがタッチ液晶なのかという設定ができます。

image

タッチ入力を選択すると、全画面にこんな風な表示がでます。image

これを、タッチ液晶のところまで Enter キーで動かし後、タッチ。設定を保存すれば、メインディスプレイでなくてもタッチ液晶が正しく認識されます。

タッチ液晶が2枚あったときにはどうなるのか?は不明ですが、ひとまず1枚のときはこれで良さそうです。

カテゴリー: windows 8.1 | セカンドディスプレイのタッチを有効に働かせる方法 はコメントを受け付けていません

本ごとに Kindle Cloud Reader へのリンクをスタート画面に作る方法

ブラウザで Kindle 本を読む方法とスタート画面へのピン留め | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6311

の続きです。

IE からショートカットを作ってスタート画面にタイル表示できることは分かったのですが、どうせならば、本のアイコンが表示されて欲しいですよね。タイトルが変えられるとはいえ、すべて「k」になってしまうのでは、どれがどの本か分からなくなってしまいます。

image

が、少し手間を掛けるとアイコンの登録もできます。

■URLショートカットを作成する

[InternetShortcut]
IDList=
URL=http://read.amazon.co.jp/?asin=<asin>
IconFile=http://images-jp.amazon.com/images/P/<asin>?.09.MZZZZZZZ
IconIndex=1

 

メモ帳などで、<タイトル>.url というファイルを作成します。これは、IE9 とは違って、昔のURLショートカットでブラウザで表示する URL とアイコンを指定しています。<asin>なところは、Kindle 本の ASIN コードを入れます。IconFile 自体は、amazon の商品画像を指定しています。

IE9 で作るショートカットは、Web サイトをピン留めする方法 にある通り website ショートカットなんですね。なるほど。開くと何故か IconFile が書き換わるので、スタート画面のアイコンが変更されてしまうという仕様のようです。なので、*.website ファイル自体を読み取り専用にすれば同じことができます。

作成したショートを プログラムの中に移動させます。

image

このフォルダは Win+R で「shell:programs」で開けます。私の場合は Kindle というフォルダを作ってその中にいれています。

ここにコピーすると、スタート画面で「新しいプログラムが…」が出るので、ちまちまとスタート画面にピン留めをすればできあがり。ピン留自体と順番を変えるのが非常に面倒なのですが、まあ、

アイコン自体が、デスクトップ用の小さな画像になってしまうので、視認性が悪いのが難点。登録自体は、Amazon Web Service を利用すればいいので、さほど難しくないでしょう。たぶん、Excel VBA とかを使ってもできそう。

スタート画面のタイル自体のカスタマイズは、以下でできるのでもう少しなんとかなりそう。

デスクトップ アプリのスタート画面のタイルをカスタマイズする方法 (Windows ランタイム アプリ) (Windows)
http://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/dn449733.aspx

他にも、仮のストアアプリを登録しておいてサブタイルでもできるでしょう。まあ、漫画本ばっかりずらずらと並ぶのもアレなのでカテゴリごとのランチャーアプリを作るほうが良いかも。大量に URL ショートカットを作るのも面倒だし、シリーズ毎に分けられると積読が少なくなるでしょう。あとは参考用の洋書まわりとか。

カテゴリー: 雑談 | 本ごとに Kindle Cloud Reader へのリンクをスタート画面に作る方法 はコメントを受け付けていません

ブラウザで Kindle 本を読む方法とスタート画面へのピン留め

Windows で Kindle を読む方法と言えば、日本語Windows 8 Pro で Kindle を動かす方法 な感じで、Android のエミュレータ Bluestacks などを使う方法しかなかったのですが、先日 amazon.co.jp から Kindle Cloud Reader が出ました。

アマゾン、PC ブラウザで読めるKindle Cloud Reader 提供開始。漫画・雑誌と洋書のみ – Engadget Japanese
http://japanese.engadget.com/2014/09/22/pc-kindle-cloud-reader/

記事では「漫画と洋書のみ」となっていますが、画像キャプチャの雑誌系や、いくつかの横書きの日本語本は読めます。順次、コンバートということなので、そのうち対応されるかもしれません(縦書きが面倒なので対応されない、というパターンもありますが)

image

多少画面は荒いですが、漫画が読めるのと洋書が PC で読めるのは便利です。手元にあるのは、Kindle whitepaper と iPad なので、普段は Kindle、ちょっと大きめなもので読むときは iPad を使っています。

image

液晶ディスプレイで並列に表示しながら使えるのは結構便利ですね。これはデスクトップ版の IE で表示してますが、Windows ストア アプリアプリ版のモダンIEのほうでも表示ができます。

■スタート画面に指定の本をピン留めする

いくつか手順…と制限がありますが、スタート画面に Kindle 本をピン留めできます。

 

多少、面倒臭い(苦笑)のは後でツール化するとして、http://read.amazon.co.jp/?asin=<ASIN> の形式で指定の本を開くことができます。この asin は amazon の商品コードで一意に決まっているものです。
Kindle 本を開いたときに、登録情報の ASIN を見ると、「B00AA9W658」のようなコードがあります。

image

これを http://read.amazon.co.jp/?asin=B00AA9W658 のようにすれば、「ヨコハマ買い出し紀行」の1巻が Cloud reader で開かれます。購入していない場合は、左下に「完全版を入手」と出るので、サンプルを開いていることがわかりますね。ちなみに、私は紙のほうを持っているので Kindle のほうは買ってません。

image

さて、購入した本の場合、これをいちいちブラウザで打つのは面倒なのでスタート画面にピン留めします。IE の左上のアイコンをデスクトップへドラッグするとショートカットができます。

image

このショートカットをメモ帳で開くと、こんな感じに URL が指定されています。

image

適当にタイトルを変えておけばよいでしょう。

image

ここに ASIN が書かれているので、これを書き換えれば、指定の Kindle 本を呼び出すことができます。また amazon の登録情報の表示以外にも URL にも ASIN が含まれているので、そこから抜き出すことも可能です。http://www.amazon.co.jp/%E3%83%A8%E3%82%B3%E3%83%8F%E3%83%9E%E8%B2%B7%E3%81%84%E5%87%BA%E3%81%97%E7%B4%80%E8%A1%8C%EF%BC%88%EF%BC%91%EF%BC%89-%E3%82%A2%E3%83%95%E3%82%BF%E3%83%8C%E3%83%BC%E3%83%B3KC-%E8%8A%A6%E5%A5%88%E9%87%8E%E3%81%B2%E3%81%A8%E3%81%97-ebook/dp/B00AA9W658/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1411541708&sr=1-1&keywords=%E3%83%A8%E3%82%B3%E3%83%8F%E3%83%9E%E8%B2%B7%E3%81%84%E5%87%BA%E3%81%97%E7%B4%80%E8%A1%8C この中の dp/ の後ろにあるコードが ASIN なので、これを抜き出します。

ショートカット自体を、スタート画面にピン留めするには、いくつか方法がありますが、次のように作れます。

  1. Win+R で、shell:programs と入力して、スタートメニュー/プログラムのフォルダを表示する。
  2. Kindle のようなフォルダを作って、作成したショートカットをコピーする。
  3. スタート画面に「新しいアプリがインストールされました」と出るので、アプリ画面から、指定のアイコンをスタート画面へピン留めする。

image

こうすると、アイコンは変わりませんが、スタート画面から直接 Kindle 本を起動できます。

image

まあ、欠点は

  • (おそらく)デフォルトのブラウザが起動されるので、モダンIE に設定しておかないと駄目?
  • アイコンが変更できない。

ってところです。ただ、Kindle にたくさんの本がある場合はちょっと便利かと。特に漫画のシリーズ本なんかはたくさんの本が並ぶので、1冊ごとにアイコンがあると便利…かもしれません。

アイコン自体は IconFile で指定されているのですが、これを変更してもアイコンは変わりません。と言いますか、元の Kindle 以外のアイコンはうまく出ません。ライブラリごとに本をまとめたりすると便利そうなので、別途簡易アプリを作るほうがいいかもしれませんね。

ちなみに Kindle では送り先の端末が制限されていますが、この Kindle Cloud Reader は制限の内に入っていないようです。そのうち、制限されるような気がしないでもないのですが、ブラウザでよんでいる限り、何台の PC でも利用できそうです。英語版の Kindle on PC はどうだったのかな?

一応、Kindle Cloud Reader も送り先に出てくるので、これで1台カウントみたいですね。

image

ちなみに初代 Surface RT でも動いています。横向きだとロードがかかって重たいですが、縦置きだとサクサク進みます。

埋め込み画像への固定リンク

カテゴリー: 雑談 | ブラウザで Kindle 本を読む方法とスタート画面へのピン留め はコメントを受け付けていません

CloudFlash を無線LANルータに接続して使う(ネットワーク参加させる)

CloudFlash をデジカメではない環境で動かそう | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6277

の続きです、CloudFlash は WiFi のホスト機能を持っていてデフォルトで SSID が「Cloud Flash」にして接続ができます。多少チープな環境ですが、写真をダウンロードできる web サーバを積んでいるので、ブラウザから写真がダウンロードできて便利です。
普通は、デジカメに CloudFlash を差して使うところですが、私の場合は SD カードをリーダを使うことで「単体」で CloudFlash を動かします。…意味があるのかどうかは不明ですが(苦笑)、ひとまず、

  • 特別な機器なし(カードリーダーは必要だけど)に WiFi 付きの Linux 環境が使える。
  • ストレージは SD メモリで拡張できるので、うまくやれば .NET が動く?
  • 初代 Surface からターミナルで接続しよう

ってのが目標です。

■CloudFlash を無線LAN 環境に参加させる

デフォルトでは、CloudFlash がホストになっていますが、これだといちいちノートPCやスマートフォンの接続先を変更しないので少々面倒です(逆に外にいるときは便利なんですけど)。なので、既存のネットワークに参加させるように設定し直します。

設定自体は、日経Linuxの2014/08号を参考にするか、以下の記事を読み進めます。

Flucard Pro – Wi-Fi 機能搭載 SD カードを Linux サーバーとして楽しむ方法
http://netbuffalo.doorblog.jp/archives/4811269.html

普通はネットワークに接続するだけでは意味がないので、自動起動時にスクリプトを動かすようにするのですが、単純に WiFi させるだけならば以下のスクリプトを autorun.sh にして SD メモリのルートに置きます。

– autorun.sh
– APP/wifi.conf
– APP/wpa.conf

#!/bin/sh

APP_HOME=/mnt/sd/APP
LOG=$APP_HOME/log.txt
SCAN=$APP_HOME/scan.txt

# echo "---" >> $LOG
# date       >> $LOG
# ifconfig   >> $LOG

. $APP_HOME/wifi.conf
ifconfig mlan0 down
sleep 3
a1 
sleep 3
ifconfig mlan0 up || exit 1
sleep 3

wpa_supplicant -i mlan0 -B -c $APP_HOME/$WPA_CONF
ifconfig mlan0 $IPADDR netmask $NETMASK  
route add default gw $GATEWAY  

sync
exit 0

起動時の動作は適宜 APP/log.txt に書き込んでいるのですが、Windows のドライブとの同期がうまく取れないときがあります。そのような時は、一度 SD カードを抜き差しして再度確認してください。一応 sync で同期させているのですが、完全ではないようです。

ESSID_NAME=<接続先のSSID>
WPA_CONF=wpa.conf
BOOTPROTO=static
IPADDR=172.16.0.99
NETMASK=255.255.255.0
GATEWAY=172.16.0.1
network={
	ssid="<接続先のSSID>"
	key_mgmt=WPA-PSK
	proto=WPA
	pairwise=TKIP
	group=TKIP
	#psk="<password>"
	psk=ff2ba81ca3ce58f606fd99998cf54271d3af00f36b371b235b7f53c0438e51a8
}

ひとまず固定IPにしてネットワークに参加させます。wifi.conf と wpa.conf の書き方は Linux 系のネットワークを調べるとよいでしょう。通常の Linux のものがそのまま使えます。

どうやら、autorun.sh スクリプト内にある a1 スクリプトが肝で、カーネルライブラリをロードしているようです。他にも w1 というスクリプトがあるので、どちらかを使えばいいんでしょう。

# cat a1
ifconfig mlan0 down

insmod /lib/ar6000.ko
sleep 1
insmod /lib/ka2000-sdio.ko
sleep 1
#iwconfig mlan0 txpower 8
#ifconfig mlan0 up
#dev=ath0
dev=mlan0

#iwpriv $dev version
#iwpriv $dev httxcfg 0x62
#iwpriv $dev htcapinfo 0x1820000

# cat w1
#insmod /mnt/sd/ka2000-sdio.ko
insmod /lib/ka2000-sdio.ko

#iwpriv mlan0 version
#iwpriv mlan0 httxcfg 0x62
#iwpriv mlan0 htcapinfo 0x1820000
#

こうすると、無線ルータにネットワーク参加して「172.16.0.99」で接続ができます。CloudFlash 自体は telnetd が自動で起動されるようになっているので(スクリプト自体は、/etc/init.d 内にあります)、tera term などで接続が可能です。ただし、ユーザー名、パスワードがない状態なので、社内 LAN などの公共のものに接続する場合は注意してください。中身が覗けてしまいますから。

■busybox が使われている

CloudFlash のメモリは 30MB弱しかありません。

組み込み Linux & 簡易 Web サーバーとして動くので、まあこれで十分といえば十分です。コマンド自体は組み込み用の busybox が使われているので、うまくマウントしてやれば機能を増やすことができます。SD カードのストレージ自体はたくさんありますから。
ストレージを活用して、Ruby を入れている例もあるので、ひょっとすると .NET Framework が乗るかもしれません。ARM で動いているそうなので、Raspberry Pi でビルドしたものを持ってくるか、QEMU 環境でビルドしたものをコピーすればよいでしょう。

■ファイル等は Windows からコピーできる

autorun.sh 等のファイルは、Windows PC からコピーできます。普通に SD メモリカードを USB リーダーに差し込んで PC に接続すればドライブとして認識がされます。

CloudFlash では /mnt/sd の環境が、SD メモリのルートになります。ここに適当にフォルダやファイルをコピーして起動時に、ln -s 等してやれば Ruby などを動かすことができます。CloudFlash の中身自体は ROM になっているので、起動時にこの作業が必ず必要になります。

ちなみに date 自体は起動時に 2012-1-1 にリセットされているようで、日付をチェックするにはちょっと特殊な操作が必要かもしれません。

また、ファイル自体は FAT32 フォーマットなので、Linux 特有のグループ設定などはできないと思われます。

■元の WiFi 環境に戻すにはどうするのか?

ブラウザを使って Auto WiFi を OFF にすることはできたのですが、元の ON に戻すには(CloudFlash を WiFi のホストとして機能させるには)どうしたらいいのかと悩みました。何故か、どこにも書いていない。
と思ったら、実は簡単です。

SD メモリカードをクイックフォーマットすれば OK です。

初期状態では、WiFi のホストとして機能しているので、確かにそうだった。結構悩んで、元に戻す設定を3時間ほど探していました。フォーマットすると JPEG などの写真データも一緒に消えてしまうので(フォルダ等が残っている状態でも駄目なようです)、きれいさっぱりフォーマットします。どうやらクイックフォーマットでよさそうです。実験としてはホスト用とネットワーク参加用の2種類のメモリカードを用意しておけばよいでしょう。
CloudFlash 自体のリセットは、SD カードリーダーに抜き差しすることで可能です。10秒ぐらいまてばいいみたいですね。

カテゴリー: 開発 | CloudFlash を無線LANルータに接続して使う(ネットワーク参加させる) はコメントを受け付けていません

CloudFlash をデジカメではない環境で動かそう

image

先日、CloudFlash というのを知って、ちょっと買ってみました。デジカメに入れて WiFi でデータを飛ばして PC で受け取ることができる、というものです。以前話題になったときに興味はあったのですが、デジカメもあまり使わなくなったので、忘れていました。日経 Linux 2014年08月号 に @netbuffalo さんの記事があって、この CloudFlash をホットスポットにつなげて使うという記事があり、中身が Linux ということが分かりました。なるほど、Linux + WiFi 環境ならば単体で Linux 環境が手にはいるのでは?と思ったわけです。

■電源供給だけで動くのか?

CloudFlash と同じ製品はいくつかあって、もともとがデジカメに差し込んで使う製品です。中身の Linux を弄ろうとする人は稀らしくて、デジカメで動くけど、PC のハブに差し込んだらどうなのか? 電源だけならどうなのか?という話はあまりないんですよね。

結論から言うと

  • 電源供給だけでは(たぶん)動きません。
    コンセントに差し込んだ、充電用ハブに SD カードアダプタを差し込んだけど、CloudFlash はうんともすんとも言いません。
  • PC のハブに差し込むときは、SD カードアダプタとの相性があります。
    私の場合、一番左のサンワサプライ ADR-SDU2L だけが動きました。
    真ん中の2つは100円ショップで買ったものですが、動きませんでした。
  • デジカメの場合は、全然大丈夫です。

私の場合、一番右の SD カードアダプタを持っていました。100円ショップで買ったもので、普通に SD メモリが読めていたから、これでいけるのでは?と思っていたものの、動かず…ひょっとしたら、デジカメオンリーなのかと思って @netbuffalo さん に尋ねたところ、SD カードアダプタでも動くことが判明。そんな訳で、上記の SD カードアダプタを買ったわけです。

相性が悪いのかどうかわかりませんが、サンワの ADR-SDU2L(500円で買った)は動いて、100円ショップの3つは動きません。正確には、左から2番目の SD カードリーダーは、最初動いたような感じなのですが、後から動かなくなりました。

電源供給の場合には動かず、SD カードリーダーやデジカメで動く。またデジカメがスリープした状態では動かない(WiFi が切れる)ところを見ると、CloudFlash 内蔵のチップとデジカメ(あるいは PC )がやり取りをしていて、それが切れるとスリープ状態に入るようです。あと、おそらくデジカメのほうが電力は安定しているでしょうから、デジカメのメモリ程度の安定性が必要なのかもしれません。

■試しに Raspberry Pi の USB につなげてみると

CloudFlash となんらかのやり取りをしていれば良いのであれば、Raspberry Pi にそれを肩代わりsてい良いわけです…ってことで、Raspberry Pi の USB につなげてみました。

結果は、CloudFlash のホストは見れるのですが(iPhone から Wifi の探索でチェックしています)、いざ繋げて写真などをダウンロードしようとすると WiFi が落ちます。RasPi に無線 LAN をつなげていることもよくある現象なので、これと同じ感じですね。たぶん、途中で電力が足りなくなって WiFi が落ちてしまっているようです。外部電源のハブをつなげるとうまくいくかもしれません。

■telnet がつながる

ip が 192.168.1.1 固定ですが、telnet がつながります。

image

ただ、これだといちいち CloudFlash をホストにして接続しないといけないので、結構面倒です。ホットスポット(自宅の無線LANネットワーク)に参加させる方法は、先の日経 Lunix の記事にあるので後で試してみます。ルートに autorun.sh を作ってやる方法なので、汎用性があってよいと思います。

CloudFlash に差し込むメモリ自体は、/mnt/sd  で覗くことができます。ftp もつながるそうなので、比較的簡単に内部にはアクセスできそうです。Linux コマンドは BusyBox が使われていました。

BusyBoxって何ぞや?:組み込みLinuxで際立つ「BusyBox」の魅力 (1/2) – MONOist(モノイスト)
http://monoist.atmarkit.co.jp/mn/articles/0802/04/news114.html

ただし、vi も動かない貧弱な環境なので、この環境のままで何かやるのは難しそうです。

image

image

デジカメ内部でRubyを動かす狂気!無線LAN内蔵SDカードアダプタPQI Air Cardの間違った使い方
http://hitoriblog.com/?p=12627

Ruby が動くのだから Mono も動かしたい、と思ったり。
# この記事をみると、電源供給だけで動いているのですが…私の手元のやつだと動かないんですよね。PQI だから動くのかも。

~~

追記:2014/09/16
グリーンハウス SDXC対応USB2.0カードリーダ/ライタ ホワイト GH-CRSDXC と CloudFlash の組み合わせで行けました。さすが「あつをリーダー」ッ!!!
これで、電源供給だけで CloudFlash を操作できます。

カテゴリー: 雑談 | CloudFlash をデジカメではない環境で動かそう はコメントを受け付けていません

F#でOpenCvSharpを使ってカメラキャプチャする

OpenCvSharp を使ってカメラキャプチャをする | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6258

の F# 版です。WPF で作ってあります。

module MainApp

open System
open System.Windows
open System.Windows.Controls
open FsXaml
open OpenCvSharp.CPlusPlus
open OpenCvSharp.Extensions

type MainWindow = XAML<&quot;MainWindow.xaml&quot;>

let mutable _frame:Mat = null

/// <summary>
/// カメラを表示
/// </summary>
/// <param name=&quot;id&quot;></param>
let camera(id:int) =
    let cap = new VideoCapture()
    cap.Open(id)
    if cap.IsOpened() then
        let fs = FrameSource.CreateCameraSource(0)
        let win = new Window(&quot;camera&quot;)
        let frame = new Mat()
        _frame <- frame
        let mutable loop = true
        while loop do
            cap.Read( frame )
            if frame.Empty() = false then
                win.ShowImage( frame )
                let key = Cv2.WaitKey(100)
                if key = 27 then
                    loop <- false
            else
                loop <- false

let loadWindow() =
   let window = MainWindow().CreateRoot()
   let accessor = MainWindow.Accessor(window)
   // ボタンクリック時のイベント
   accessor.btnCamera.Click.Add( fun e -> camera(0) )
   accessor.btnCapture.Click.Add( fun e -> 
        accessor.img.Source <- WriteableBitmapConverter.ToWriteableBitmap(_frame)
       )
   // ウィンドウを返す
   window

[<STAThread>]
(new Application()).Run(loadWindow()) |> ignore

やっていることは、C# 版と同じで、カメラ用のウィンドウを開くのとボタンを押したときにキャプチャする処理が入っています。ファイルに保存する処理はほとんど同じなので省略。

F# で WPF を扱うときは FsXaml のタイププロバイダを使います。ボタンイベントとかはボタン自身に名前を付けて Add.Click 等で追加すれば ok.
フォームの場合は Bitmap に落とすのに BitmapConverter.ToBitmap を使いますが、WPF の Image.Source に対しては WriteableBitmapConverter.ToWriteableBitmap を使って Mat から WritableBitmap に落とします。
Mat と Bitmap の相互変換と、float/double で処理した自前の Pixcels クラスを使えば、画像解析のトライアンドエラーがしやすいかなと、奮闘中です。もう少しできたら github にでも。

ひとまず、動作サンプルはこちら。直ぐ動くように opencv の dll も含んでいるのでちょっと大きいです。

カテゴリー: F#, OpenCV | F#でOpenCvSharpを使ってカメラキャプチャする はコメントを受け付けていません

クラス名はUMLスタンダードに則って作るのがベター

 

気になったので、ラショナルプロセス風なUMLスタンダードパターンを紹介しておきます。

Amazon.co.jp: ラショナル統一プロセス入門 第3版 (ASCII Software Engineering Series): フィリップ クルーシュテン, Philippe Kruchten, 藤井 拓: 本

  1. ユースケース等で対象のオブジェクトを抽出する。
  2. オブジェクトを辞書化する。
  3. 辞書を整理して、オブジェクト図を作成する。
  4. オブジェクト図を抽象化して、クラス図を作成する。
  5. クラス図を作成した後に、GoF などのパターンがあれば、それに準じる。

統一プロセス自体には 5 番目のパターン適用はありません(GoF の前のため)。このため、GoF などのパターン(特に Java のエンタープライズパターンなど)が既にある状態での、現在では Manager などの「パターン特有の単語」が頻出していますが、もともとはパターン適用時の単語なので変更しては駄目なんですよ。

最初にユースケースからオブジェクトを抽出するプロセスでは、具象的な名前を使います。これは、オブジェクト図(具象図)とクラス図(抽象図)を明確に区別するためでもあり、いきなりモデル化してしまうことにより、間違った抽象化を避けるためです。今でいえば、ドメイン駆動などがあるので、業務ドメインに特化した言語/単語を使いつつ、クラス図にて抽象化(一般化した名前)に落ち着けるか、ドメインに特化した名前をそのまま使うか、の判断を行います。このプロセスは、2 の辞書化の部分にもあてはまります。

そんな訳で、「今」しか学ばないと名称に混乱するでしょうが、「歴史」的なGoF 等のパターンにでてくる名称と統一プロセスを知っておくと、特に悩むことはありません。抽象化と具象化の部分が区別されますからね。なんか、ちょっと Twitter でのコメントが気になったので、書いておきます。

~~

余談ですが、名称をつけるときのテクニックは「明確」にあります。昔よりも IDE のインテリセンス/補完機能が働いているので、統一的な名称を単語の前に出すことで、うまくマッチせることができます。たとえば、本に関係するメソッドは、

  • ListBook
  • SortByBookID
  • GetBookTitle

とするよりも

  • BookList
  • BookSortByID
  • BookTitleGet

な風にすると揃えられます。Get/Set のように動詞を前にするか後ろにするかは異論があるでしょうが、それは業務ドメインによって判断してください。もちろん、この「Book」の場合、Book クラスを作っておいて、メソッド/プロパティでまとめる、ってのが王道ですが(そのあたりが、オブジェクト指向なんですけど)。

カテゴリー: 開発 | クラス名はUMLスタンダードに則って作るのがベター はコメントを受け付けていません

OpenCvSharp を使ってカメラキャプチャをする

画像解析まわりを F# で組もうとする場合、OpenCV の Mat と相互変換しなくちゃいけません。OpenCV 自体は C++ ベースなのでロジックを C++ で組むのがベータなのですが、ちょっとトライ&エラーがやりづらいんですよね。OpenCV の機能自体を使うのであれば、そのまま OpenCvSharp を使えばいいのですが、内部ロジックを弄る必要がある(特にテンプレートマッチの関数とか特徴量の関数とか)予定なので、できるだけデータ変換はおこしたくないな、と思っていました。

■OpenCvSharp は導入が簡単である

shimat/opencvsharp
http://github.com/shimat/opencvsharp
OpenCvSharpをつかう その17(NuGetで導入) – schima.hatenablog.com
http://schima.hatenablog.com/entry/2013/12/15/110513

OpenCvSharp 自体を知ったのは検討したのは3年前ぐらいで、その頃ちょうど .NETラボで亀川さんが講演していて、OpenCvSharp あたりを使った画像解析の話だったんですよね。データの変換自体が、C++ のネイティブなポインタと、.NET Framework のラッピングされたポインタでは、点単位ではひどく遅くなるだろうという会話をしたのを覚えています。その頃は、導入が結構面倒(OpenCvのDLL自体が面倒)だったので、C++ で組んでも C# で組んでもあまり変わりがなかったのですが、いつの間にか(失礼)、NuGet で設定ができるようになっていました。

Nuget で「OpenCvSharp」で検索してインストールすると、必要な DLL とプロジェクトの設定が自動的に行われます。

現状の OpenCV は 2.49(3のほうは、まだアルファ版です)なのですが、これらが一気に dll フォルダにダウンロードされます。

C++ プロジェクトで組むときに、最初に面倒なのがこの DLL を導入する(いちいちバージョンを変えないといけない)ことなので、プログラミング時の敷居がぐっと下がっています。

■カメラの画像をキャプチャする

サンプル自体は、先の github の中
https://github.com/shimat/opencvsharp/tree/master/sample

にあるので、目的のものを動かしてみるとよいでしょう。もともと OpenCV に含まれているサンプルが C#/VB 版に書き直されている感じです。

サンプルコードはこちら
http://1drv.ms/1lREkUV

■カメラへの接続

カメラへの接続は VideoCapture で設定すれば ok です。capture.Read あたりも C++ 版と同じなので、OpenCv を使っている場合はだいたい想像がつくでしょう。このウィンドウは OpenCv が勝手に作るウィンドウなので、Cv2.WaitKey でキー待ちをしてエスケープキーで閉じるようにしておきます。また、このウィンドウはスレッドで動いているらしく、async/await とか createwindows しなくても、モーダレスで動きます。これはこれで便利。

void Camera()
{
    var capture = new VideoCapture();
    // 最初のカメラを取得
    capture.Open(0);
    if (!capture.IsOpened())
        throw new Exception("capture initialization failed");
    var fs = FrameSource.CreateCameraSource(0);
    using (var normalWindow = new Window("normal"))
    {
        var normalFrame = new Mat();
        var srFrame = new Mat();
        while (true)
        {
            capture.Read(normalFrame);
            if (normalFrame.Empty())
                break;

            _frame = normalFrame;
            normalWindow.ShowImage(normalFrame);
            int key = Cv2.WaitKey(100);
            if (key == 27) break;   // ESC キーで閉じる
        }
    }
}

■カメラから画像をキャプチャ

カメラから Bitmap へ落とすのも非常に簡単です。BitmapConverter.ToBitmap でフレームを渡してやれば Bitmap で落とせます。これをそのままピクチャボックスに張り付ければ画像が出ます。ここの BitmapConverter は以前とは違って OpenCvSharp.Extensions の中に入っているそうです。

private void button2_Click(object sender, EventArgs e)
{
    // カメラからキャプチャ
    Bitmap bitmap = BitmapConverter.ToBitmap(_frame);
    this.pictureBox1.Image = bitmap;
}

■ファイルに保存する

以前作ったツールから流用して、Bitmap を PNG 形式にして保存します。日付と連番でファイル名を付けるので

/// <summary>
/// マイピクチャに保存
/// </summary>
/// <param name=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
private void button3_Click(object sender, EventArgs e)
{
    var bmp = (Bitmap)pictureBox1.Image;
    var fmt = ImageFormat.Png;
    var path = MakeFileName( fmt );
    bmp.Save(path);
    label1.Text = Path.GetFileName(path);
}

string FOLDER = @&quot;d:workblogimage&quot;;

string MakeFileName(ImageFormat fmt)
{
    string path = FOLDER;
    DateTime dt = DateTime.Now;
    string dname = string.Format(&quot;{0:0000}{1:00}{2:00}&quot;, dt.Year, dt.Month, dt.Day);
    var files = System.IO.Directory.GetFiles(FOLDER);
    var file = files.Where(f => f.IndexOf(dname + &quot;_&quot;) > 0).Max();
    var ext = fmt.ToString();
    if (ext == ImageFormat.Jpeg.ToString()) // 拡張子を変更
    {
        ext = &quot;jpg&quot;;
    }
    if (file == null)
    {
        path += dname + &quot;_01.&quot; + ext;
    }
    else
    {
        var mat = new Regex(@&quot;_(\d+)&quot;).Match(file);
        int num = int.Parse(mat.Groups[1].Value);
        num++;
        path += dname + &quot;_&quot; + num.ToString(&quot;00&quot;) + &quot;.&quot; + ext;
    }
    return path;
}

と、こんな感じにしておけば、手軽に Web カメラから画像へ落とせるようになります。
あとで、テンプレートマッチング用の関数のスピードも確認しておきましょう。これができると、ほぼ F# で組めるので。

カテゴリー: C#, OpenCV | 2件のコメント

画像認識のプレ加工に F# を使う

最終的には OpenCV と組み合わせるはずなのですが、いちいち C++ で組むのも面倒なので、事前加工の部分を F# で組みます。

image

こんな画像をグレースケールに変えたり、2値化するだけですね。

imageimage

imageimage

■画像加工にパイプを使う

C++ で OpenCV を使っていた頃から考えていたのですが、画像加工のフィルタ部分はパイプ(>>)を使うとスムースです。当然フィルタなんだから、画像関係の多種の filter と同じなので当然といえば当然。

        let path = @&quot;D:\work\PiVistion\src\PiVision\FsVision.Test\data&#92;&#48;01.bmp&quot;
        let pi = FsVision.LoadForm( path )
        // グレースケール
        pi |> Pixel.toGray 
           |> FsVision.SavePixel( @&quot;D:\work\PiVistion\src\PiVision\FsVision.Test\data&#92;&#48;01-pi-gray.bmp&quot; )

F# では、こんな風に |> を使ってつなげます。

■PowerPack を使うかどうか?

The Old F# “PowerPack” – Home
https://fsharppowerpack.codeplex.com/
fsprojects/powerpack
https://github.com/fsprojects/powerpack

画像加工の場合、2次元マトリクスが頻発するので、F# powerpack を使うのがベターなんでしょうが、要素として RGBA を使わないといけないので、Matix<RGBA> と定義したいんですよね。が、が、なんとなくうまく動かない。Matrix<‘T> になっているけど、実質 Matirx<float> しか動かないようです。RGBA を別々に扱っても良いのですが、試してみると F# の List#Item は結構遅くて、短時間に 640×480 の画素数を処理するのは難しそうです。シーケンシャルに for it in lst do な感じでイテレータアクセスすれば結構なスピードで動きます。まあ、有限要素法の件もあるし、マトリクス関係は自作しましょう、ということで powerpack 無しで作っています。

どちらかというと、OpenCV の各種関数を F# から使うところに力を入れた感じ。

■RGB/YUV/YIQ/HSV の相互変換

Zaku認識(2) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/601

かつて Zaku 認識(4年も前の記事になるのか)をやろうと思って、色相とか輝度とかを扱ったので、これの F# 版も作っておきます。3×3 か 4×4 のマトリクスなんだが、これをいちいち自前の matrix に通すと遅いので、直接計算します。さほど手間ではないし。

 
type RGB = { R:float; G:float; B:float; }
type YUV = { Y:float; U:float; V:float }
type YIQ = { Y:float; I:float; Q:float }
type HSV = { H:float; S:float; V:float }

module Pixel =

    type Conv =
        static member toYUV (rgb:RGB) =
            let y =  0.299 * rgb.R +  0.587 * rgb.G +  0.114 * rgb.B 
            let u = -0.169 * rgb.R -  0.331 * rgb.G +  0.500 * rgb.B 
            let v =  0.500 * rgb.R + -0.419 * rgb.G -  0.081 * rgb.B 
            { Y=y; U=u; V=v }
        static member toRGB (yuv:YUV) =
            let r =  1.000 * yuv.Y +  0.000 * yuv.U +  1.402 * yuv.V 
            let g =  1.000 * yuv.Y -  0.344 * yuv.U -  0.714 * yuv.V 
            let b =  1.000 * yuv.Y +  1.772 * yuv.U +  0.000 * yuv.V 
            { R=r; G=g; B=b }
        static member toYIQ ( rgb:RGB ) =
            let y = 0.2990 * rgb.R + 0.5870 * rgb.G + 0.1140 * rgb.B
            let i = 0.5959 * rgb.R - 0.2750 * rgb.G - 0.3210 * rgb.B
            let q = 0.2065 * rgb.R - 0.4969 * rgb.G + 0.2904 * rgb.B
            { Y=y; I=i; Q=q }
        static member toRGB ( yiq:YIQ ) =
            { R = 1.001 * yiq.Y + 0.955 * yiq.I + 0.622 * yiq.Q;
              G = 0.999 * yiq.Y - 0.272 * yiq.I - 0.648 * yiq.Q;
              B = 1.004 * yiq.Y - 1.106 * yiq.I + 1.704 * yiq.Q; }
        static member toHSV ( yiq:YIQ ) =
            { H = System.Math.Atan2(yiq.I, yiq.Q) ;
              S = Math.Sqrt( yiq.I * yiq.I + yiq.Q * yiq.Q) ;
              V = yiq.Y; }
        static member toYIQ ( hsv:HSV ) =
            { Y = hsv.V; 
              I = hsv.S * Math.Sin( hsv.H ) ;
              Q = hsv.S * Math.Cos( hsv.H ) ; }
        static member norm (rgb:RGB) =
            let r = if rgb.R < 0.0 then 0.0 else if rgb.R > 1.0 then 1.0 else rgb.R
            let g = if rgb.G < 0.0 then 0.0 else if rgb.G > 1.0 then 1.0 else rgb.G
            let b = if rgb.B < 0.0 then 0.0 else if rgb.B > 1.0 then 1.0 else rgb.B
            { R=r; G=g; B=b }

    let map (f:(RGB->RGB)) (pi:pixels) =
        pixels [ 
            for row in pi.Data do
                yield [ for it in row do
                            yield f( it )
                        ]] 
    /// <summary>
    /// gray scale filter
    /// </summary>
    /// <param name=&quot;pi&quot;></param>
    let toGray (pi:pixels) =
        pi |> map ( fun x ->
            // 加重平均 
            let c = (0.896 * x.R + 1.76 * x.G + 0.34 * x.B) / 3.0
            { R=c; G=c; B=c } )
    
    let to2Value (ce:float) (pi:pixels) =
        pi |> map ( fun x ->
            let c = (0.896 * x.R + 1.76 * x.G + 0.34 * x.B) / 3.0
            if c <= ce then { R=0.; G=0.; B=0. } else { R=1.; G=1.; B=1. }  
            )

    /// <summary>
    /// sepia filter
    /// </summary>
    /// <param name=&quot;pi&quot;></param>
    let toSepia (pi:pixels) =
        pi |> map ( fun x -> 
            let r = 0.393 * x.R + 0.769 * x.G + 0.189 * x.B
            let g = 0.349 * x.R + 0.686 * x.G + 0.168 * x.B
            let b = 0.272 * x.R + 0.534 * x.G + 0.131 * x.B 
            { R=r; G=g; B=b } |> Conv.norm)


こっちはいずれ整理して github に上げる予定です。

カテゴリー: F# | 画像認識のプレ加工に F# を使う はコメントを受け付けていません

麻雀牌認識のプロセスを考える

image

■目的

こんな画像から、14牌を認識する、とする。この画像自身の切り出しをどうするのか?って問題があるけど、麻雀牌自体は手元に置くことが多いし、ある程度画像認識の範囲を絞り込むことができるだろう…という仮定からスタートする。もちろん、これは「仮定」なので、前提条件が間違っている場合も頭の隅に入れておく。

■手順を考察

いきおい、牌の物体認識から入ってしまうと思われるが、それは駄目だ。というか無駄だ。牌の形は「四角」で固定されているし、牌の表面は主に白でおおわれている。さらに背景は、白以外(大抵は緑のマット?)なのだから、わざわざ物体認識という大層なことをやらなくてもいい。白っぽい部分を抽出すれば、牌と特定できるだろう。

さらに、この場合は牌が14個連なっている。多少上下にずれているが、だいたいは真ん中で一直線になっている。牌の数は決まっていて、14個であるのだから、先に大まかな位置が分かったら、単純に14等分すればそれぞれの牌の位置がわかるだろう。もちろん、上下のずれ、左右のずれ(カメラ位置のずれ)などを考慮するために若干ずらした牌の位置でも確認が必要になる。

牌の大まかな位置がわかったら、個別の牌を認識させる。これは特徴量抽出かテンプレートマッチングでよい。たぶん、テンプレートマッチングでも十分なスピードが出るのではないだろうか?牌の種類自体は、たかだか9×3+7=28種 花牌などを入れれば36種しかない。アルファベットよりも少ない。大文字小文字を区別する必要もないし、似ている文字(ゼロとオーとか)もないので、ほとんど誤認識はせずに済むだろう。教師画像は多少の上下の揺れと、上下さかさまの画像を用意しておけばよい。グレースケールのテンプレートマッチング法で十分だと思う。

赤牌をどう認識するかだが、これはテンプレートマッチングした後にあらためて色で識別すればよい。伍萬など決まっているから、それで特定ができる。

牌が特定できたら、後は自由に待ちとかを計算すればOK。

■認識の流れ

  1. 背景色とは異なる、白っぽい部分を特定する。
  2. 白っぽい部分は、横長と仮定する(先行きは、縦長やななめでも良い)
  3. 白っぽい横長の牌並びの、左端と右端の位置を特定する。
  4. 左端と右端で14分割する。
  5. 14分割した牌の位置に対して、テンプレートマッチングする。テンプレートマッチは上下逆さまの場合と上下の位置の揺れも教師画像として用意する。
  6. 牌の特定ができる。

これでやってみよう。

カテゴリー: OpenCV | 麻雀牌認識のプロセスを考える はコメントを受け付けていません