Queueのどうでも良い話
thread.rbでQueue#.popがこのように定義されている。
def pop(non_block=false) @mutex.synchronize{ while true if @que.empty? raise ThreadError, "queue empty" if non_block @waiting.push Thread.current @mutex.sleep else return @que.shift end end } end
そこで、次のようなコードを実行すると
require 'thread' queue = Queue.new t = Thread.start do loop{ queue.pop } end 2.times do nil until t.stop? t.wakeup end nil until t.stop? queue.instance_eval{ p @waiting } p queue.num_waiting
以下のようになる。
[#<Thread:0x00000001899698 sleep>, #<Thread:0x00000001899698 sleep>, #<Thread:0x00000001899698 sleep>] 3
本当にどうでも良い。
cvAvgを用いた標本分散フィルタ
指定したサイズのROIをずらしながら、ROI内の画素の標本分散を出力するフィルタを書いた。
#include <math.h> #include "cv.h" #include "highgui.h" void VarianceFilter(IplImage *src, IplImage* dst, int w_size); int main(int argc, char *argv[]){ IplImage *img, *dst; img = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE); /* 画像をグレースケールで読み込む */ dst = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1); VarianceFilter(img, dst, 3); /* 標本分散フィルタ */ cvSaveImage("result.jpg", dst, 0); /* 結果画像の保存 */ /* メモリの解放 */ cvReleaseImage(&img); cvReleaseImage(&dst); return 0; } /* 標本平均フィルタ 引数: src: 入力画像 dst: 出力先 w_size: ウィンドウサイズ */ void VarianceFilter(IplImage *src, IplImage* dst, int w_size){ int i, j, wi, wj; double avg, e; uchar f; for(i=0; i<src->height; i++){ for(j=0; j<src->width; j++){ cvSetImageROI(src, cvRect(j, i, w_size, w_size)); /* ROIをセット */ avg = cvAvg(src, NULL).val[0]; /* ROI内の画素の標本平均 */ /* 標本分散の計算 */ e = 0.0; for(wi=i; wi<i+w_size; wi++){ for(wj=j; wj<j+w_size; wj++){ f = CV_IMAGE_ELEM(src, uchar, wi, wj); e += pow(avg-f, 2); } } e /= w_size * w_size; dst->imageData[dst->widthStep * i + j] = e; /* 出力 */ } } cvResetImageROI(src); /* ROIの解除 */ return; }
cvCalcHistを用いたエントロピーフィルタ
最近OpenCVを始めて、ふとエントロピーフィルタを書いてみようと思い立った。
ここではROIをずらしながらcvCalcHistでヒストグラムを求めるエントロピーフィルタについて書く。
#include <math.h> #include "cv.h" #include "highgui.h" void EntropyFilter(IplImage *src, IplImage* dst, int w_size); int main(int argc, char *argv[]){ IplImage *img, *dst; img = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE); /* 画像をグレースケールで読み込む */ dst = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1); EntropyFilter(img, dst, 3); /* エントロピーフィルタ */ cvSaveImage("result.jpg", dst, 0); /* 結果画像の保存 */ /* メモリの解放 */ cvReleaseImage(&img); cvReleaseImage(&dst); return 0; } /* エントロピーフィルタ 引数: src: 入力画像 dst: 出力先 w_size: ウィンドウサイズ */ void EntropyFilter(IplImage *src, IplImage* dst, int w_size){ int i, j, k, hist_size = 256; double e, f, e_max; float range[] = { 0, 256 }; float *ranges[] = { range }; CvHistogram *hist; hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, 0, 1); /* ヒストグラムを生成する */ f = 1.0 / (w_size*w_size); e_max = f * log(f) * w_size * w_size; /* エントロピーの最大値 */ for(i=0; i<src->height; i++){ for(j=0; j<src->width; j++){ cvSetImageROI(src, cvRect(j, i, w_size, w_size)); /* ROIをセット */ cvCalcHist(&src, hist, 0, NULL); /* ヒストグラムを計算する */ /* エントロピーの計算 */ e = 0.0; for(k=0; k<256; k++){ if(f = cvQueryHistValue_1D(hist, k)){ f /= w_size*w_size; e += f * log(f); } } dst->imageData[dst->widthStep * i + j] = e/e_max*255; /* 0〜255で正規化して格納 */ } } cvResetImageROI(src); /* ROIの解除 */ cvReleaseHist(&hist); /* ヒストグラムを解放する */ return; }
ウェザーニューズから受信した緊急地震速報をeew_parserに通して何かする
WNIから受信した緊急地震速報をeew_parserに通して色々するクラス
WNI_EEW.newにWNIのメールアドレスとパスワードとブロックを渡すと、WNIから緊急地震速報を受信した時にその緊急地震速報から生成したEEWParserオブジェクトをブロックに渡して実行してくれる。
require 'socket' require 'eew_parser' require 'digest/md5' require 'open-uri' class WNI_EEW DEBUG = true trap(:INT) do exit end def initialize(user_id, pass, &b) http = TCPSocket.open(get_server_addr, 80) http.print "GET /login HTTP/1.0\r\nX-WNI-Account: #{user_id}\r\nX-WNI-Password: #{Digest::MD5.hexdigest(pass)}\r\n\r\n" begin if WNI_HTTPHeader.new(http.readline("\n\n"))["X-WNI-Result"] == "OK" debug "[#{Time.now.strftime("%F %T")}] #{get_server_addr} との接続を確立しました" else abort "認証に失敗しました。" end rescue => ex abort "接続に失敗しました。#{ex.message}" end loop do case WNI_HTTPHeader.new(http.readline("\n\n"))["X-WNI-ID"] when "Keep-Alive" debug "[#{Time.now.strftime("%F %T")}] Keep-Alive" when "Data" http.readline("\n\x02\n\x02\n") yield EEWParser.new(http.readline("9999=").strip) end end http.close end def debug(str) puts str if DEBUG end def get_server_addr open('http://lst10s-sp.wni.co.jp/server_list.txt') do |list| list.read.lines.to_a.sample[0..-5] end end class WNI_HTTPHeader def initialize(str) @lines = str.lines.to_a end def [](key) @lines[1..-2].each do |line| field = line.split(":", 2) return field.last.strip if field.first == key end end end end WNI_EEW.new('WNIのメールアドレス', 'WNIのパスワード') do |eew| # ここで何かする end
WNIのサーバはHTTPのヘッダフィールド名の大文字小文字を区別するので、net/httpは使えない。
仕方が無いのでTCPSocketを使って通信している。
高度利用者向け緊急地震速報の電文を扱う為のライブラリeew_parser
ウェザーニューズなどから受信した高度利用者向け緊急地震速報の電文を扱う為のRubyライブラリを書きました。
https://github.com/Glasssaga/eew_parser
require "eew_parser" str = <<EOS # 緊急地震速報の電文 37 03 00 110415233453 C11 110415233416 ND20110415233435 NCN005 JD////////////// JN/// 251 N370 E1408 010 66 6+ RK66324 RT01/// RC13/// EBI 251 S6+6- ////// 11 300 S5+5- ////// 11 250 S5+5- ////// 11 310 S0404 ////// 11 311 S0404 ////// 11 252 S0404 ////// 11 301 S0404 ////// 11 221 S0404 ////// 01 340 S0404 ////// 01 341 S0404 ////// 01 321 S0404 233455 00 331 S0404 233457 10 350 S0404 233501 00 360 S0404 233508 00 243 S0403 ////// 01 330 S0403 233454 00 222 S0403 233455 00 9999= EOS fc = EEWPaser.new(str) puts <<EOS 電文種別コード: #{fc.type} 発信官署: #{fc.from} 訓練等の識別符: #{fc.drill_type} 電文の発表時刻: #{fc.report_time} 電文がこの電文を含め何通あるか: #{fc.number_of_telegram} コードが続くかどうか: #{fc.continue?} 地震発生時刻もしくは地震検知時刻: #{fc.earthquake_time} 地震識別番号: #{fc.id} 発表状況(訂正等)の指示: #{fc.status} 発表する高度利用者向け緊急地震速報の番号(地震単位での通番): #{fc.number} 震央地名コード: #{fc.epicenter} 震央の位置: #{fc.position} 震源の深さ(単位 km)(不明・未設定時,キャンセル時:///): #{fc.depth} マグニチュード(不明・未設定時、キャンセル時:///): #{fc.magnitude} 最大予測震度(不明・未設定時、キャンセル時://): #{fc.seismic_intensity} 震央の確からしさ: #{fc.probability_of_position} 震源の深さの確からしさ: #{fc.probability_of_depth} マグニチュードの確からしさ: #{fc.probability_of_magnitude} 震央の確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_position_jma} 震源の深さの確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_depth_jma} 震央位置の海陸判定: #{fc.land_or_sea} 警報を含む内容かどうか: #{fc.warning?} 最大予測震度の変化: #{fc.change} 最大予測震度の変化の理由: #{fc.reason_of_chaage} EOS fc.ebi.each do |local| puts "地域コード: #{local[:area_cord]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{local[:arrival_time]}" puts "警報を含むかどうか: #{local[:warning]} 既に到達しているかどうか: #{local[:arrival]}" end
このようなコードを書くと、
電文種別コード: マグニチュード、最大予測震度及び主要動到達予測時刻の高度利用者向け緊急地震速報(グリッドサーチ法、EPOS自動処理手法) 発信官署: 東京 訓練等の識別符: 通常 電文の発表時刻: 2011-04-15 23:34:53 +0900 電文がこの電文を含め何通あるか: 1 コードが続くかどうか: true 地震発生時刻もしくは地震検知時刻: 2011-04-15 23:34:16 +0900 地震識別番号: 20110415233435 発表状況(訂正等)の指示: 通常発表 発表する高度利用者向け緊急地震速報の番号(地震単位での通番): 5 震央地名コード: 福島県浜通り 震央の位置: N37.0 E140.8 震源の深さ(単位 km)(不明・未設定時,キャンセル時:///): 10 マグニチュード(不明・未設定時、キャンセル時:///): 6.6 最大予測震度(不明・未設定時、キャンセル時://): 6強 震央の確からしさ: 防災科研システム(5点以上)[防災科学技術研究所データ] 震源の深さの確からしさ: 防災科研システム(5点以上)[防災科学技術研究所データ] マグニチュードの確からしさ: 全点P相(最大5点)[気象庁データ] 震央の確からしさ(気象庁の部内システムでの利用): テリトリー法(2点)[気象庁データ] 震源の深さの確からしさ(気象庁の部内システムでの利用): グリッドサーチ法(5点)[気象庁データ] 震央位置の海陸判定: 陸域 警報を含む内容かどうか: true 最大予測震度の変化: 最大予測震度が1.0以上大きくなった 最大予測震度の変化の理由: M及び震源位置が変化したため 地域コード: 福島県浜通り 最大予測震度: 6弱から6強 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 茨城県北部 最大予測震度: 5弱から5強 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 福島県中通り 最大予測震度: 5弱から5強 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 栃木県北部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 栃木県南部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 福島県会津 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 茨城県南部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: true 既に到達しているかどうか: true 地域コード: 宮城県南部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: false 既に到達しているかどうか: true 地域コード: 千葉県北東部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: false 既に到達しているかどうか: true 地域コード: 千葉県北西部 最大予測震度: 4 予想到達時刻: 警報を含むかどうか: false 既に到達しているかどうか: true 地域コード: 群馬県南部 最大予測震度: 4 予想到達時刻: 2011-04-15 23:34:55 +0900 警報を含むかどうか: false 既に到達しているかどうか: false 地域コード: 埼玉県南部 最大予測震度: 4 予想到達時刻: 2011-04-15 23:34:57 +0900 警報を含むかどうか: true 既に到達しているかどうか: false 地域コード: 東京都23区 最大予測震度: 4 予想到達時刻: 2011-04-15 23:35:01 +0900 警報を含むかどうか: false 既に到達しているかどうか: false 地域コード: 神奈川県東部 最大予測震度: 4 予想到達時刻: 2011-04-15 23:35:08 +0900 警報を含むかどうか: false 既に到達しているかどうか: false 地域コード: 山形県置賜 最大予測震度: 3から4 予想到達時刻: 警報を含むかどうか: false 既に到達しているかどうか: true 地域コード: 埼玉県北部 最大予測震度: 3から4 予想到達時刻: 2011-04-15 23:34:54 +0900 警報を含むかどうか: false 既に到達しているかどうか: false 地域コード: 宮城県中部 最大予測震度: 3から4 予想到達時刻: 2011-04-15 23:34:55 +0900 警報を含むかどうか: false 既に到達しているかどうか: false
こんな風に解析してくれます。
gem install eew_parser
でインストールできます。
詳しくはドキュメントを参照して下さい。
配列のようなものを可読な状態で保存
最近はロイディという人工無脳を弄って遊んでいる。
本家ロイディは、ログと単語の保存をバイナリな内部ファイルと、human readableな外部ファイルに分けて保存し、外部ファイルに変更があればそれを内部ファイルに反映するという少し面倒な事をしているので、これを改善しようと思い立った。
人間が読めてかつRubyのオブジェクトとしての復元も可能な形で保存が出来れば、内外の区別を廃して1つのファイルにまとめる事ができる。
必要としては、n番目の要素を取り出せ、末尾に要素を追加出来ればそれで良かった。
まず思いついたのがYAML::Storeだったが、何もかも1つのYAMLドキュメントに突っ込む仕様である為、トランザクションの出入りを行う度に巨大なYAMLドキュメントを読み書きする事になり、メモリの消費も激しく、遅い。
そこでYAMLドキュメントを細かく分け、必要な部分だけをロードするようにした。
#n番目の要素を取り出す def [](n) n += @size if n < 0 #末尾からのインデックス File.open(@filename) do |f| f.each_line("\n---") do |s| return YAML.load(s) if f.lineno > n end end end
新たな要素をpushしたい時は、追加したい要素をYAML.dumpしてファイルに追記するだけでよい。
複数のロイディが同じファイルを共有して動作する事は想定していないので、ファイルのロックもしないし、トランザクションという概念もないが、用途には十分であった。
慶應義塾大学の学生がDreamSparkで幸せになる方法
ac.jpなアドレスを持っていない学生は以下の方法でDreamSparkできる。
- https://www.dreamspark.com/ に適当なLiveアカウントでログインしておく。なければ作る。
- http://linno.jp/ でkeio.jpのメールアドレスを使って適当にアカウントを作る。
- http://linno.jp/campaign/dreamspark から「ダウンロード」と書いてあるボタンをクリック
これで認証され、無料にてダウンロードができる。
受験生の皆さんはac.jpなメールアドレスをくれるまともな大学を選んだ方が良いと思います。