YARDで拡張ライブラリのドキュメントを書くときはメソッドの定義のところで@overloadタグを書かなきゃダメという話

はじめに

まぁ表題のとおりなんですが、要は
「YARDで拡張ライブラリのドキュメントを書くときは、@overloadタグでメソッドシグニチャを書かないと正しくドキュメントが生成されないので注意しましょう」
という話です。

環境

何が起こったかというと

拡張ライブラリで、Hashを渡すメソッドのドキュメントをYARDでこんな感じで書いてたんですよ。

/*
 * @param [Hash] opts parameters
 * @option opts [Number] :arg1 argument 1
 * @option opts [Number] :arg2 argument 2
 */
VALUE rb_foo(VALUE self, VALUE opts) {
  return Qnil;
}

で、

$ yardoc foo.c

とかやって作成したドキュメントを意気揚々と開いたわけですよ。

そしたらなんと、@optionで指定した :arg1 と :arg2 のドキュメントが出てこないじゃないですか。

f:id:ser1zw:20120430181745p:image

で、どうしたかというと

YARDのリポジトリにIssue登録を投げてみたら、
「CのコードでYARDを使うときは@overloadタグでメソッドシグニチャとかパラメータの記述をしないとちゃんと認識できねーよ」
との回答を頂いたので、こんな感じに書きなおしてみました。

/*
 * @overload foo(opts)
 *   @param [Hash] opts parameters
 *   @option opts [Number] :arg1 argument 1
 *   @option opts [Number] :arg2 argument 2
 */
VALUE rb_foo(VALUE self, VALUE opts) {
  return Qnil;
}

そしたらちゃんと@optionタグで指定した :arg1 と :arg2 の内容が表示されてました。

f:id:ser1zw:20120430181912p:image

まとめ

というわけで、YARDを拡張ライブラリで使う場合は@overloadタグをつけましょうね!というお話でした。

HWエンキューでロックされているセグメントを特定する

はじめに

Oracleまわりのトラブルの調査のため、HWエンキューでロックされたセグメントを特定する方法を調べてみました。

環境

HWエンキューってなんぞ?

Oracleのエンキューとは

エンキューは、データベース・リソースへのアクセスをシリアライズする共有メモリーの構造(ロック)です。
(Oracleエンキュー名)

です。
HWエンキューは、セグメントのHWM(High Water Mark; 最高水位標)を動かすときに行われるロックです。保持されているロック情報を示すV$LOCKビュー上では、TYPE='HW'のレコードとして表されます。

HWエンキューでロックしているセグメントを特定する

1. ロックされたHWエンキューが待っているデータのファイルとブロックを特定

まず、V$LOCKからTYPEが'HW'の行を探し、そのデータブロックアドレスのファイル番号とブロック番号を取得します。

HWエンキューの場合、V$LOCKのID1, ID2は下記のようになります。

  • ID1: HWMが変更されるセグメントが格納されている表領域の番号
  • ID2: セグメントヘッダの相対データブロックアドレス

(パフォーマンス・ビューを使用したインスタンスのチューニング - HWエンキュー)


また、ストアドファンクションDBMS_UTILITY.DATA_BLOCK_ADDRESS_FILEとDBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCKにデータブロックアドレスを渡して実行すると、そのデータブロックアドレスのファイル番号とブロック番号がわかります。

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのファイル番号部分を返す
(DATA_BLOCK_ADDRESS_FILEファンクション - DBMS_UTILITY)

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE (
   dba NUMBER)
  RETURN NUMBER;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのブロック番号部分を返す
(DATA_BLOCK_ADDRESS_BLOCKファンクション - DBMS_UTILITY)

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK (
   dba NUMBER)
  RETURN NUMBER;


そこで、V$LOCKのID2をDATA_BLOCK_ADDRESS_FILEとDATA_BLOCK_ADDRESS_BLOCKに渡せばよさそうです。
SQLはこんな感じになります。

SELECT
     DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(ID2) "FILE_ID",
     DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(ID2) "BLOCK_ID"
FROM
     V$LOCK
WHERE
     TYPE = 'HW'

結果はこんな感じ。ファイル番号とブロック番号がわかりました。

FILE_ID BLOCK_ID
20 29


2. ロックしているセグメントを特定
1.でわかったファイル番号とブロック番号から、HWエンキューでロックしているセグメントを特定します。
こんな感じのSQLを実行します。

SELECT
     OWNER,
     SEGMENT_NAME,
     SEGMENT_TYPE
FROM
     DBA_EXTENTS
WHERE
     FILE_ID = 20
AND 29 BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1

WHEREの条件の値(上記の20と29)には、1.で調べたものを入れてください。
結果はこんな感じ。

OWNER SEGMENT_NAME SEGMENT_TYPE
ORACLE SYS_LOB000001234C01234$$ LOBSEGMENT

どうやら SYS_LOB000001234C01234$$ というセグメントがロックされているらしい、ということがわかりました。
この情報をもとに原因を特定して、対策を行いましょう。

まとめ

HWエンキューでロックされているセグメントを特定する方法を調べてみました。
これでHWエンキューでずーっとロックされてエラいことになっても大丈夫ですね!

Scientific Linux 6.2にOracle XE 11g R2をインストールする

はじめに

Scientific LinuxOracleのデータベースをインストールしたので、手順を書いておきます。

環境

  • Scientific Linux 6.2 x86_64
    • インストール時のパッケージ選択では Basic Server を選択
  • Oracle Database Express Edition 11g Release 2

手順

1. まずはダウンロード
下記からパッケージをダウンロードします。
Oracle Database Express Edition 11g Release 2のダウンロード
Windows用(32bit版)とLinux用(64bit版)がありますが、今回はLinuxに入れるので
Oracle Database Express Edition 11g Release 2 for Linux x64
のほうをダウンロードしてきます。
f:id:ser1zw:20120319004941p:image
ダウンロードにはOracleのユーザ登録が必要です。事前にこのあたりから登録してください。


2. 必要なパッケージをインストール
と言ってもScientific LinuxをBasic Serverとしてインストールしたら、特に何もしないで大丈夫でした。
公式のドキュメントによると、

  • glibc should be greater than or equal to 2.3.4-2.41
  • make should be greater than or equal to 3.80
  • binutils should be greater than or equal to 2.16.91.0.5
  • gcc should be greater than or equal to 4.1.2
  • libaio should be greater than or equal to 0.3.104

http://docs.oracle.com/cd/E17781_01/install.112/e18802/toc.htm#BABHICJH

が必要らしいので、無い場合はyumなどでインストールしてください。


3. Oracleをインストールする
まずはダウンロードしたファイル(oracle-xe-11.2.0-1.0.x86_64.rpm.zip)を展開して、中身を確認します。

$ unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip
$ ls
Disk1  oracle-xe-11.2.0-1.0.x86_64.rpm.zip
$ cd Disk1/
$ ls
oracle-xe-11.2.0-1.0.x86_64.rpm  response  upgrade

中にrpmパッケージが入っているので、rootでインストールします。

$ su
パスワード:
# rpm -ivh oracle-xe-11.2.0-1.0.x86_64.rpm 
準備中...                ########################################### [100%]
   1:oracle-xe              ########################################### [100%]
Executing post-install steps...
You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.

次に、 /etc/init.d/oracle-xe configure を実行しろとのことなので、実行しましょう。
途中、

  • Application Expressのポート番号(デフォルトは8080)
  • データベースリスナーのポート番号(デフォルトは1521)
  • DBのアカウントのパスワード(SYSとSYSEMもこのパスワードになる)
  • OS起動時にOracleを起動するかどうか(デフォルトはyes)

について聞かれるので、適宜設定します。

# /etc/init.d/oracle-xe configure

Oracle Database 11g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 11g Express 
Edition.  The following questions will determine whether the database should 
be starting upon system boot, the ports it will use, and the passwords that 
will be used for database accounts.  Press <Enter> to accept the defaults. 
Ctrl-C will abort.

Specify the HTTP port that will be used for Oracle Application Express [8080]:

Specify a port that will be used for the database listener [1521]:

Specify a password to be used for database accounts.  Note that the same
password will be used for SYS and SYSTEM.  Oracle recommends the use of 
different passwords for each database account.  This can be done after 
initial configuration:
Confirm the password:

Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]: 

Starting Oracle Net Listener...Done
Configuring database...Done
Starting Oracle Database 11g Express Edition instance...Done
Installation completed successfully.

成功したようです。rootでの作業はここまで。


4. 環境変数を設定する
ORACLE_HOMEなどの環境変数の設定です。下記のシェルスクリプトで必要なものを設定してくれるようになっています*1

/u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

というわけで、Oracleを使うユーザの.bashrcに以下の1行を追加するだけで完了です。

. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

念のため、.bashrcを読みなおしておきましょう。

$ source ~/.bashrc

これでパスの設定などが行われ、sqlplusが使える状態になります。


5. 動作確認する
sqlplusを起動し、systemでログインしてOracleのバージョンを表示してみます。
パスワードは手順3.の途中で入力したものを入れればOKです。

$ sqlplus system

SQL*Plus: Release 11.2.0.2.0 Production on 日 3月 18 01:24:57 2012

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

パスワードを入力してください: 


Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
に接続されました。
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

うまくいったっぽいですね。

まとめ

そんなわけで、Scientific LinuxにOracle XE 11g R2をインストールしてみました。
特にハマることもなく、すんなりインストールできるもんですね。

*1:これはbash用のものですが、同じディレクトリにcsh用の oracle_env.csh も用意されています

Sinatra(というかRack)で複数の同名パラメータを受け取る

はじめに

Sinatra

  http://localhost:4567/?foo=123&foo=456&foo=789

って感じで複数の同名パラメータを送ったら

require 'sinatra'
get '/' do
  params[:foo] #=> 789
end

のように、最後の1つしか取ってくれませんでしたf**k!
そんなわけで、全部取り出すにはどうすればいいのか調べてみました。

環境

結論から言うと

そもそもSinatra(というよりRack)では、複数の同名パラメータを受け取る場合は

  http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789

のように、キーの後ろに [] をつけるのが正解のようです。
こうすると、

require 'sinatra'
get '/' do
  params[:foo] #=> ["123", "456", "789"]
end

のように、値を配列で取り出すことができます。このあたりはたぶんRailsでも一緒です。

そんなのヤダヤダ、という場合は?

  http://localhost:4567/?foo=123&foo=456&foo=789

という形式でパラメータが渡された場合でも同様の動作にするには、

Rack::Utils.parse_query(qs, d = nil)

でパラメータの文字列(上記でいうと foo=123&foo=567&foo=789)をバラしてやればOKです。


パラメータの文字列は、

  • GETの場合:
@env['rack.request.query_string']
  • POSTの場合:
@env['rack.request.form_vars']

に格納されています。
というわけで、

require 'sinatra'
# http://localhost:4567/?foo=123&foo=456&foo=789 でアクセス

get '/' do
  # GETのときは @env['rack.request.query_string']
  hoge = Rack::Utils.parse_query(@env['rack.request.query_string'])
  hoge['foo'] #=> ["123", "456", "789"]
end

post '/' do
  # POSTのときは @env['rack.request.form_vars']
  hoge = Rack::Utils.parse_query(@env['rack.request.form_vars'])
  hoge['foo'] #=> ["123", "456", "789"]
end

のようにすれば、キーの後ろに [] が無い場合でも複数の同名パラメータを扱えます。
ただし、この場合は

  http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789

のように指定されると、キー名が 'foo[]' と解釈されます。

require 'sinatra'
# http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789 でアクセス

get '/' do
  hoge = Rack::Utils.parse_query(@env['rack.request.query_string'])
  hoge['foo'] #=> nil
  hoge['foo[]'] #=> ["123", "456", "789"]
end

まとめ

  • Sinatra(というかRack)で複数の同名パラメータを使うときは ?foo[]=1&foo[]=2 みたいにキーの後ろに [] をつける
  • Rack::Utils.parse_queryでパラメータの文字列を自前でバラせば ?foo=1&foo=2 みたいなのも扱える

続・CI超入門〜Jenkinsのススメ2 CI導入の壁を越えろ〜 に行ってきました。

はじめに

2月22日に行われた「続・CI超入門 〜 Jenkinsのススメ2 CI導入の壁を越えろ 〜」に行ってきました。

Jenkinsの導入 (CloudBees, Inc. 川口 耕介さん)

CIやJenkinsを導入するにあたってのお話でした。
デモで出てきたTest Driveを使えば、手軽にJenkinsを試せそうです。

継続的インテグレーション(CI)の発想
  • ビルドを頻繁に実行しよう
  • テストを頻繁に実行しよう
  • 問題が発生したらときすぐに発見できるようにしよう
CIとは
  • 命綱
  • 火災報知機
    • 問題があったらすぐにわかる
    • 普段ちゃんと動いていることが前提(「警報鳴ってるけど、いつものことだからいいよ」って感じになってしまう)。問題が見つかったらすぐに直すことが必要。
CIするのにあるとよいもの
  • バージョン管理システム
    • 誰の変更で壊れたのかわかるようにするため
  • 自動化されたビルドスクリプト
    • ビルドがない言語の場合は品質検査で代用
  • 自動化されたテストスクリプト
デモ
  • ジョブを作る
    • 新規ジョブ作成 > ジョブ名を入れて選ぶ(フリースタイルがおすすめ)
    • ジョブとは?
      • 基本的にはソフトウェアのビルドを模している
      • ビルドするのにどんな条件・ツールなのかがわかるのも利点の1つ。ログを見るのを手助けする役割もある。
      • テストを実行して失敗すると、どのコミットのせいなのか、とかそのときのエラーメッセージ、スタックトレースも表示される

Jenkins + EC2で分散ビルド (Sky株式会社 玉川 竜司さん)

ビルドは負荷の変動が激しい作業のため、Amazon EC2上で動かしてしまおうというお話でした。

Amazon EC2でJenkinsを動かす話
  • ビルドは負荷の変動が激しい(リリース前は高負荷、とか)
  • Amazon EC2ならピークにあわせてハードウェアを用意しなくていい!!
    • EC2で勝手にスレーブを動的に増減してくれる
    • 1時間ごとの従量課金
  • セキュリティは大丈夫?→Amazon Virtual Private Cloud(VPC)やDirect Connectで対応
EC2 Pluginで高負荷時にスレーブを自動的に起動
  • EC2 Pluginを使えば、EC2のインスタンスを自動的に起動・終了してくれる
  • 注意点
    • 設定はちょっと引っかかるかも
    • UbuntuのAMIをベースにするとうまくいった
    • 64bitインスタンスは今のところ使えない

LT(1): Startup Jenkins! 〜CIから始めないJenkins入門〜 (@kanu_さん)

JenkinsはCIだけでなく、高機能なcronとしても使えるというお話でした。その発想はなかった!
紹介されていたTracLightningを使えば導入も非常に簡単にできそうです。

CIできてないとJenkinsに入門できない?→否!
  • 高機能cronとして使える
  • Windowsのタスクがイケてない→そうだ、Jenkinsを使おう!
    • スケジュールとかログとかの管理も楽だし実行結果とかもWeb UIから見れる。処理が終わったらメール送信も可能。
TrachLightningを使えば5分で導入完了
  • JenkinsやらTracやら必要なものがひと通り揃っている
  • Jenkinsのビルドサンプルもたくさん付属

LT(2): <すいませんタイトル忘れました> (@cactusmanさん)

Jenkinsをどうやって社内に導入するか、というお話でした。
様々な工夫がありましたが、最終手段は「会社を変える」だそうですw

構想編
  • コストをかけない
    • ダメならすぐ撤退
  • 何がしたいかを決めておく
    • テストがしたいのか、常にリリースできる状態を保ちたいのか
サーバ編
  • 空いているサーバを確保
  • どっかに寄生
  • 上司を説得するには実際に動くものを見せるのが効果的
    • グラフとか。マネージャの人はそういうの大好きなので。
ビルド編
  • ビルドスクリプトは書きましょう
  • 静的解析ツールを動かすのに使うのもアリ
通知編
  • まずは自分だけ
    • いきなり失敗してるのがみんなに通知されると、何事か!?となるので
  • 安定してきたらみんなが見る場所へ

まとめ

Jenkinsを簡単に試せるTest DriveやTracLightningのことを知ることができたり、Jenkinsを定期実行ジョブや静的解析ツールを動かすために使うというアイディアなど、いろいろ学ぶことができました。
そんなわけで、早速Jenkinsをインストールしていろいろ試してみようと思います。

*1:手元のUbuntu11.10ではファイルを右クリックして「別のアプリで開く」→「IcedTea Java 6 Web Start」で実行できました

logstudy01 & mailerstudy02に行ってきました

rsyslog入門 @ttkzw さん

syslogの概要や問題点、rsyslogの特長や設定方法などを解説していただきました。

syslogとは
  • カーネルやアプリケーションから通知されたイベントメッセージをログファイルに記録する仕組み
  • 問題点
    • デバイスとsyslogサーバとの通信にはUDPを使用しているため、信頼性がない→ログメッセージの取りこぼし、送信元の詐称の可能性がある
    • 暗号化できない
    • 自分でログローテートできない
    • fsyncするのでディスクIOが非効率
  • syslogのログ取りこぼしの原因は2つ
    • UPDでの通信のため、パケットの取りこぼしがある
    • CPUの負荷が高い場合は受け取ったメッセージを処理できず、メッセージが消えてしまう
代替のsyslogデーモン
  • syslog-ng: syslogと設定ファイルの互換性がない
  • rsyslog: syslogと設定ファイルの互換性がある程度維持されてる, 最近のLinuxでよく使われてる
rsyslogとは
  • syslogのフォーク
  • rsyslogの r は reliable で、メッセージ転送の信頼性を表している
  • TCPとかRELPとかRFC3195とかで通信することでメッセージ転送の信頼性が向上
  • 転送先のサーバがダウンしてる場合でも、rsyslogはメッセージをキューイングして再送してくれる(syslogはキューイングしない)
  • プラグインモジュールによる機能拡張が可能
rsyslogのバージョン
  • ver.4, 5, 6があって、5と6は開発が続いている
  • 後方互換モード(rsyslog -c0 で起動)は ver.6 でなくなったので、使いたい場合はver.5を使用
rsyslogのモジュールとか設定とかの話
  • モジュール特有のディレクティブはそのモジュールのロード後に書く
  • rsyslogの公式Webドキュメントに説明がないディレクティブが半分ぐらいあるので、名前から判断してくださいw
  • rsyslogのセレクタ拡張機能
    • [facility].=[severity] でseverityに一致するもの
    • [facility].!=[severity] で一致しないものを指定
  • アウトプットモジュールのomudpspoofは偽装した送信アドレスでUDPでメッセージを送信する。転送するときに元のアドレスで送りたいときに使うらしい。

メール暗号化入門 -アリスとボブの恋の行方- @ttkzw さん

一般的な暗号方式や暗号通信で使用されるプロトコルなどについて、解説していただきました。
2セッション続けて@ttkzwさんが担当されていました。なんという@ttkzwさん無双w

暗号技術
  • メールの脅威:盗聴、否認、改ざん、詐称→脅威への対策として暗号技術を利用
  • ほとんどはセッション鍵(一定時間だけ有効な鍵)を使って暗号化。セッション鍵を公開鍵方式で渡して、あとは共通鍵方式でやりとりする。
  • PGPは信頼の輪:友達の友達はみんな友達
  • 公開鍵暗号では鍵配送が問題となる(暗号化は常に鍵配送との戦い)
    • 対策として公開鍵証明書を使用
    • 認証局自身の証明書を証明する仕組みが公開鍵基盤(PKI)
    • ルート認証局ルート証明書はOSやソフトウェアにバンドルして配布
SSL/TLS
  • SSL/TLS: インターネット上の安全な通信を提供するプロトコル
    • TCP/IP通信に対して透過的に使える
    • ダウングレード攻撃の影響を受けるため、SSL2.0は無効にしなきゃダメ
  • SMTPS: SMTPSSL/TLSで暗号化するプロトコル
    • TCP 465番ポートを慣習的に使ってるけどIANAに正式に登録されていない(慣習的に使ってる)
    • メーラからSMTPサーバへのメール送信時のみで使われてて、SMTPサーバ同士のやりとりでは使えない
メール特有の話
  • SMTP,POP3,IMAPのセッション中にSTARTTLSコマンドでTLS通信に切り替える
    • POP3だとなぜか短縮されてて STLS になってる
  • SMTPサーバと接続確認するには
    • SMTPS: openssl s_client -connect localhost:465
    • STARTTLS: openssl s_client -connect localhost:587 -starttls smtp
  • IMAPサーバとの接続確認
    • IMAPS: openssl s_client -connect ホスト名:993
    • STARTTLS: openssl s_client -connect ホスト名:143 -starttls imap
  • POP3サーバとの接続確認
    • POP3S: openssl s_client -connect ホスト名:995
    • STARTTLS: openssl s_client -connect ホスト名:110 -starttls pop3
  • STARTTLS以外はメール特有のものはない。SSL/TLSTCP/IP通信に対して透過的に使える。

logと監視の微妙な関係 〜こんなlogはイヤだ〜 @qryuuさん

logstudyの第1回として、ログの出力方法が悪いせいでうまくログがとれないケースの実例(主にZabbix)を紹介していただきました。

資料↓
https://docs.google.com/presentation/pub?id=1wGLr5am-N4WfeXiGculVxZFdw140w18nbnkIPtmJ4W4

  • イベントビューワでは日本語のメッセージなのにZabbixで収集してみたら英語になってる!?
    • そもそもメッセージのDLLが作成されていないとか、Windows2008で追加されたWidowsイベントログ6.0を使っていると、APIの互換性が無いためZabbixで取れないとか…
  • ログローテーションすると文字化けする!?
    • ローテーションした瞬間に圧縮されてしまったため。1世代前までは圧縮しないようにして解決。
  • logが変なところで改行される!?
    • Zabbixはファイルエンドを改行として扱うため、メッセージを途中でフラッシュするとそこで改行されてしまう。途中でフラッシュしちゃダメ
  • logが遅れて出力される!?
    • syslogの仕様。-mark-オプションをつけるかrsyslogを使う

まとめ

そんなわけで、logstudy01 & mailerstudy02に行ってきました。

第5回 Ruby/OpenCV進捗報告

はじめに

気がついたら2012年になってましたが、Ruby/OpenCVもじわじわと進化を続けております。

進捗

開発リポジトリが移動しました!

GitHubでOrganizationアカウントを作って、メインのリポジトリをそっちに移してみました。
そんなわけで、今後のメインリポジトリ

ruby-opencv/ruby-opencv - GitHub

になります。

ser1zw/ruby-opencv - GitHub のほうは機能追加とかするときの作業用に使う予定です。

Windows(mingw32, mswin32)に対応しました!

ようやくWindowsでも動くようになりました。
と言ってもまだバイナリ配布はしてないので、自前でのビルドが必要です。


前提条件
OpenCVのインストールが必要です。
OpenCV2.3.1の入手、ダウンロード、インストール、環境設定 | イメージングソリューションなどを参考にインストールしてください。dllのパスの設定も忘れずに!
なお、以降の説明では、OpenCVが C:\path\to\opencvdir にインストールされているものとします。


mswin32の場合
mswin32の場合はVisual C++ (Express EditionでOK)を入れて、Visual Studioコマンドプロンプトから下記のコマンドを実行します。

$ git clone git://github.com/ruby-opencv/ruby-opencv.git  # またはGitHubからzipファイルをダウンロードして展開
$ cd ruby-opencv
$ ruby extconf.rb --with-opencv-dir=C:\path\to\opencvdir\bin\install  # 自分でビルドしたOpenCVを使う場合(バイナリ版を使う場合は下記参照)
$ nmake
$ nmake install

バイナリ配布されているOpenCVをそのまま使う場合は、includeフォルダが C:\path\to\opencvdir\build\include 、libフォルダが C:\path\to\opencvdir\build\x86\vc10\lib となるので、extconf.rb のオプションを

$ ruby extconf.rb --with-opencv-include=C:\path\to\opencvdir\build\include --with-opencv-lib=C:\path\to\opencvdir\build\x86\vc10\lib

みたいな感じにしてください。


mingw32の場合
mingw32の場合はMinGWのgcc, g++, MSYSを入れて*1、MSYSのコンソールから下記のコマンドを実行します。

$ git clone git://github.com/ruby-opencv/ruby-opencv.git  # またはGitHubからzipファイルをダウンロードして展開
$ cd ruby-opencv
$ ruby extconf.rb --with-opencv-dir=/C/path/to/opencvdir/install  # 自分でビルドしたOpenCVを使う場合
$ make
$ make install

mswin32と同様、バイナリ配布されているOpenCVを使う場合は、

$ ruby extconf.rb --with-opencv-include=/C/path/to/opencvdir/build/include --with-opencv-lib=/C/path/to/opencvdir/build/x86/mingw/lib

みたいな感じで指定してください。

ffcallが不要になりました!

これで余計な依存ライブラリがなくなり、インストールがちょっとだけ楽になりました。やったね!

今後の展開

とりあえず

  • gem install hogehoge でインストールできるようにしたい
    • rubygems.orgで公開?
    • Windows用はバイナリも配布したい
  • 全文検索機能付きのリファレンスを作りたい
    • るりまサーチ的なやつ
  • C++版の機能を追加したい
    • DescriptorMatcherとか

みたいなことを考えてます。他にもこんな機能ほしい!とかありましたらお知らせください。

デモ

cvAdaptiveThresholdのラッパーを追加したので、そのサンプルコード的なやつを書いてみます。
環境は

です。

# -*- encoding: utf-8 -*-
require 'opencv'
include OpenCV

img = IplImage.load('Lenna.jpg', CV_LOAD_IMAGE_GRAYSCALE)

# CvMat#adaptive_threshold(max_value, options = nil)
#   max_value (Integer) - 最大値
#   options (Hash) - オプションパラメータ
#     :adaptive_method - 使用するアルゴリズム (:mean_c または :gaussian_c)
#     :threshold_type - しきい値処理の種類 (:binary または :binary_inv)
#     :block_size - しきい値を計算するときのブロックサイズ
#     :param1 - 各手法で使うパラメータ
result1 = img.adaptive_threshold(255, :block_size => 25)
result2 = img.adaptive_threshold(128, :adaptive_method => :gaussian_c, :threshold_type => :binary_inv, :block_size => 5, :param1 => 10)

GUI::Window.new('original').show img
GUI::Window.new('mean_c').show result1
GUI::Window.new('gaussian_c').show result2
GUI::wait_key
GUI::Window.destroy_all

結果はこんな感じ。いい感じにしきい値処理がされています。

f:id:ser1zw:20120216003049p:image

まとめ

そんなわけで、第5回Ruby/OpenCV進捗報告でした。

リポジトリはこちら

ruby-opencv/ruby-opencv - GitHub

人柱、Pull Request、ご要望、バグ報告等は大歓迎です!

*1:インストーラからC Compiler, C++ Compiler, MSYS Basic System, MinGW Developer Toolkitあたりを入れておけば大丈夫なはず http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/