2014年6月17日火曜日

えッ! ssh_exchange_identification: read: Connection reset by peer

hosts.deny設定後

/etc/hosts.denyの各行にプロトコルとIPアドレスを追記すれば該当するアクセスを拒否することが出来る.しかし,この設定ファイルに間違いがあるとローカルからのSSHなど,あらゆるアクセスが遮断されてしまうようだった.
幸い,まだSSHで接続したままのプロセスが残っていたため,そこから修正することが出来た./etc/hosts.denyや/etc/hosts.allowを変更するときは接続中のプロセスを残すなどして対策しておくことにする;;

私の間違い

ログ(/var/log/auth.log)を確認したところ...

warning: /etc/hosts.deny, line 29: missing newline or line too long
warning: /etc/hosts.deny, line 29: all the subsequent rules will be ignored
とされていた.29行目と言えば最後の行で,newlineの単語が見える.
というわけで,最後の行に改行を入れたら大丈夫になりました.

2014年6月4日水曜日

Python: ファイル名の番号でソートする

はじめに

たとえば次のようなファイル名のリストがあったとき
track1.mp3
track2.mp3
track3.mp3
track11.mp3
track23.mp3
track30.mp3 
これをトラック番号でソートしたいと思います.

しかし,これを次のように普通にソートすると次のようになってしまいのぞましい結果とは言えません.

>>> list = [ "track1.mp3", "track2.mp3", "track3.mp3", "track11.mp3" "track23.mp3", "track30.mp3"]
>>> list.sort()
>>> list
[ "track1.mp3", "track11.mp3", "track2.mp3", "track23.mp3" "track30.mp3"]
そこで,理想通りソートできるようにします.

結論

結論から行くと次のようにしました.
ファイル名の文字列の中で,当然ながら数値の部分も文字列として扱ってソートしてしまうのが問題です.数値の部分だけを抽出して,文字列ではなく数値としてソートします.

>>> import re
>>> list = [ "track1.mp3", "track2.mp3", "track3.mp3", "track11.mp3", "track23.mp3", "track30.mp3"]
>>> list2 = [(re.search("[0-9]+", x).group(), x) for x in list]
>>> list2
[('1', 'track1.mp3'), ('2', 'track2.mp3'), ('3', 'track3.mp3'), ('11', 'track11.mp3track23.mp3'), ('30', 'track30.mp3')]

>>> list2.sort(cmp = lambda x, y: cmp(int(x[0]), int(y[0])))
>>> list2
[('1', 'track1.mp3'), ('2', 'track2.mp3'), ('3', 'track3.mp3'), ('11', 'track11.mp3track23.mp3'), ('30', 'track30.mp3')]

>>> list = [x[1] for x in list2]
>>> list
['track1.mp3', 'track2.mp3', 'track3.mp3', 'track11.mp3track23.mp3', 'track30.mp3']
できあがり(^^)v

要素を見ましょう!

文字列から数値の抽出

reモジュールをインポートしてsearch関数によって正規表現で文字列から数字の部分を抽出します.
search関数の戻り値のオブジェクトが持つgroup()を呼び出すことで一致した部分(数字)の文字列が抽出できます.この段階ではまだ文字列型です.
>>> impore re
>>> str = "track3234.mpe"
>>> m = re.search("[0-9]+", str)
>>> m.group()
3234

ファイル名とトラック番号にようるタプルの配列を作成

次のような.トラック番号とファイル名をペアにしたタプルの配列を作成しています.
[('1', 'track1.mp3'), ('2', 'track2.mp3'), ('3', 'track3.mp3'), ('11', 'track11.mp3track23.mp3'), ('30', 'track30.mp3')]

「結論」で記述したコードではまとめて書いていますが丁寧に書くとすると次のようにかけます.

import re
list2 = []
list =  [ "track1.mp3", "track2.mp3", "track3.mp3", "track11.mp3", "track23.mp3", "track30.mp3"]
for x in list:
    m = re.search("[0-9]+", x)
    tuple = (m.group(), x)
    list2.append(tuple)

これを次のようにまとめて書くことが出来ます.

import re
list = [ "track1.mp3", "track2.mp3", "track3.mp3", "track11.mp3", "track23.mp3", "track30.mp3"]
list2 = [(re.search("[0-9]+", x).group(), x) for x in list]

タプルの1つめの要素を数値型にして,比較そしてソートする

作成したタプル配列list2をソートします.
ただし単純にsort()を呼び出してもソートできないので,ソートする際の比較メソッドを独自に指定します.
 次のように引数cmpに比較関数を与えます.通常はcmp=cmp(x, y)となっており,x < yのとき-1,x == yのとき0, x > yのとき1を返す関数です.
ここではラムダ式を用いて,与えられる2つのタプルx, yの最初の要素(すなわちトラック番号)を数値型にキャストしてcmp()関数に与えています.

list2.sort(cmp = lambda x, y: cmp(int(x[0]), y[0]))

タプル配列からもとの文字列配列を作成する

最後に,タプル配列ではなく文字列配列にします.
丁寧に書けば次のように書きますね.

list = []
for x in list2:
    list.append(x[1])

これをつぎのようにまとめて書きました

list = [x[1] for x in list2]

総括

ファイル名などに番号を入れて順番を管理している際,番号の部分も文字列として扱ってしまっていることが原因で適切にソートされない場合があります.ファイル名の文字列から数字の部分だけを抽出して,数値としてソートすれば良いと言うことですね.

oO(それにしてもPythonってすごく簡単にかける・・・(^^)v...)

2014年5月14日水曜日

django (python)とJavaScriptのミリ秒単位の時間の受け渡し

はじめに

PythonのWebアプリケーションdjangoで管理している時間・時刻をJSON形式でJavaScriptに渡したり,あるいはJavaScriptからAjaxを使ってJSON形式を介してサーバ側のdjangoに渡したりします.
ここでは,年月日及び時分秒に加えミリ秒でのやりとりも行います.

サーバ側:データベースモデルの確認と準備

まず,バックエンドのデータベースシステムのDateTime型など時間型のフォーマットがミリ秒やマイクロ秒までサポートしているかどうか確認してください.MySQLでは5.6.4からマイクロ秒までをサポートしているようです.

MySQL 5.6.4 and up expands fractional seconds support for TIMEDATETIME, and TIMESTAMP values, with up to microseconds (6 digits) precision(引用 2014年5月14日)

ただ,ここではバックエンドのデータベースがミリ秒やマイクロ秒までをサポートしていない物として進めます.
そこで,DateTimeフィールドの他に,マイクロ秒を記録するフィールドを作成します.

# models.py
from django.db import models

class TimeSample(models.Model):
''' マイクロ秒を記録するために整数型フィールドのdatetime_microを設けます '''
    datetime = models.DateTimeField()
    datetime_micro = models.IntegerField(default=0)

クライアント側: dateformat.jsの準備

JavaScriptで,サーバからString型の日時を受け取りDate型に変換する必要があります.変換にはdateformat.jsが便利です.dateformat.jsはMITライセンスで配布されていますので,以下からダウンロードしましょう.

http://www.enjoyxstudy.com/javascript/dateformat/


いつもの通り,HTMLから読み込みます.
<script type="text/javascript" src="{{ static_url }}scripts/dateformat.js"></script>

クライアント側:jQueryとjQueryのJSONプラグインの準備

JavaScriptでサーバと通信したり,JSON形式を送信用に作成したり,受信時に解析したりするためにjQueryとそのプラグインを使います.以下からそれぞれダウンロードしましょう.

jQuery本体 http://jquery.com/
jQueryのJSONプラグイン https://code.google.com/p/jquery-json/downloads/list

で,HTMLに追加;;
<script type="text/javascript" src="{{ static_url }}scripts/json-x.xx.x.js"></script>
<script type="text/javascript" src="{{ static_url }}scripts/json.json-x.x.js"></script>

JavaScriptからPythonに時間を渡す(Ajax)

クライアント

クライアントからJavaScriptでサーバ側のdjango(python)に日時を渡します.jQueryの$.ajaxから非同期バックグラウンドで送信しましょう.(POSTで送る場合,CSRF関連があるかもしれませんが,個々では割愛します.)

ここでは,送信時のDateフォーマットを""yyyy-MM-dd HH:mm:ss:SSS"とします.SSSはミリ秒です.
// JavaScript
// 送信用フォーマットの日付を作成

var date = new Date(); var dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss:SSS"); var dateStr = dateFormat.format(date); var sendData = {'datetime': dateStr}; // 送信 $.ajax({ url: "http://www.xxxx.com/", type: "POST", contentType: "application/json; charset=utf-8", datatype: "json", data: $.toJSON(sendData), success: function(data) { alert("送信成功"); }, error: function() { alert("失敗"); } });

サーバ側

クライアントからJSON形式で送られてきた日時の情報を取得し,データベースに記録します.

# views.py
from models import *
from datetime import datetime
from django.http import *
import json as simplejson

def requested_json_datetime(request):
    ''' リクエストされた日時をデータベースに記録します '''

    data = simplejson.loads(request.body)
    time = datetime.strptime(data[u'datetime'], '%Y-%m-%d %H:%M:%S:%f')
    
    model = TimeSample(datetime=time, datetime_micro=time.microsecond)
    model.save()

    return HttpResponse("success")
実際にはミリ秒ですがサーバ側ではマイクロ秒のオーダーで保存します.

PythonからJavaScriptに時間を渡す

今度はサーバ側からJavaScriptにJSONで時間を渡してみましょう.

クライアント側

サーバに「時間くださいよ~!」ってリクエストしましょう.取得したJSONからDate型を作成します.
var dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss:SSS");
var date = dateFormat.parse(responsedData.datetime);

サーバ側

データベースを参照してDateTime型の値を取得します.strftime()関数でDateTimeを文字列型に変換できます.変換するときのフォーマットの指定方法はhttps://docs.python.org/2/library/datetime.html#strftime-strptime-behavior で紹介されています.
例えば次のようにすると,送信時とほぼ同じフォーマットの文字列を作成できますが,%fはミリ秒ではなくマイクロ秒であるという違いがあります.

sample = TimeSample.objects.get(id=1)
dt = sample.datetime
dt = dt.replace(microsecond=sample.datetime_micro)
str = dt.strftime("%Y-%m-%d %H:%M:%S:%f")


これではマイクロ秒でレスポンスしてしまいますので,ここでは手作業で変換しました.単純に1000で除算してマイクロ秒からミリ秒に変換しています.
sample = TimeSample.objects.get(id=1)
dt = sample.datetime
dt = dt.replace(microsecond=sample.datetime_micro)
str = "%04d-%02d-%02d %02d:%02d:%02d:%03d" % (
                                    dt.year,
                                    dt.month,
                                    dt.day,
                                    dt.hour,
                                    dt.minute,
                                    dt.second,
                                    dt.microsecond / 1000,
                                    )

ではstrをJSONにしてレスポンスしましょう.


data = {'datetime': str}
json = simplejson.dumps(data)
return HttpResponse(json)

総括

JavaScriptとPython間で日時のやりとりを行いました.年月日,時分秒までならかんたんなのですが,ミリ秒までのやりとりだと一ひねりいりますね.

2014年4月27日日曜日

OpenCV 2.4.9 ビルドと/Zmオプション(C1076)

OpenCV 2.4.9のビルド時にC1076エラーが発生した

Windows + VC11ビルドでC1076, C3859エラー

OpenCV2.4.9をWindowsでVisual C++2012(VC11)を用いてビルドしたところ次のエラーがopencv_contrib, opencv_stitchingで発生しました.コレに追随して依存しているモジュールもビルドが出来ませんでした.

error C1076: コンパイラの制限 : 内部ヒープの上限に達しました。上限を変更するには /Zm オプションを使用してください。

error C3859: PCH の仮想メモリの範囲が超えています。'-Zm118' 以上のコマンド ライン オプションで再コンパイルしてください。




このC1076というエラー「このエラーは、シンボルが多すぎるか、テンプレートのインスタンス生成が多すぎることが原因で発生する場合が」あるそうです.(参照)

というわけで該当したopencv_contrib, opencv_stitichingに/Zmオプションを追加してみます.

/Zmオプションの追加

opencv_contribとopencv_stitchingのプロパティそれぞれを開き
「C/C++」→「コンパイラオプション」を開き/Zmオプションを追加します.


また,Debug, Releaseの共通するオプションであるため,「構成」を「すべての構成」にします.

エラーではZm118以上を指定するようにされていました.数値が多きほど割り当てられるメモリ量が大きくなるようですね.ここでは150を指定してみます./Zmと150の間に空白をいれません.

/Zm150と追加したところ

総括

OpenCV2.4.9のビルドではopencv_contribとopencv_stichingに/Zmオプションを追加してビルドします.(たしかOpenCV2.4.8でもいくつかのモジュールに同様の設定を行わなければいけなかったはず...)


2014年4月24日木曜日

OpenNIついに閉鎖か...orz..

OpenNIがついに閉鎖,こんな閉鎖の仕方なの??

OpenNIが2014年4月23日をもって閉鎖と発表されています.前日の22日にはトップページに閉鎖を告げる告知が成されていました.私も大慌てでOpenNIやNiTEなどをダウンロードしておきました.もう永久保存版ですね.

で,閉鎖前日のOpenNIのサイトwww.openni.orgにアクセスするとこのようなページでした.↓
www.openni.org 閉鎖前日(2014/04/23)

デカデカと閉鎖の告知がされていました.

Important
Software downloads will continue to be avaiirable until April 23rd 2014 at which time the OpenNI website will be closed.


その後,平成26年4月24日(木)の午前3時頃再びアクセスしてみると...
えッ,,,まさかのエラー↓(自宅のネットワークが落ちたわけじゃないよなぁ..と確認しつつ..)

まさか,サーバ毎突然アクセスできなくなるとは...!(O_O)
なかなかやりますな....そして残念です.


個人的にはWindows XPのサポートを終えたマイクロソフト社のように何らかの告知をしばらく続けるのかと思いきや,そんなこと成しにいきなりサーバが消えました..

マイクロソフトのWindows XPサポートページ(2014/04/24現在)

深度センサのXtion Pro Liveには末永くお世話になるつもりだったので残念です.
この分野は現在,めざましく技術革新を続けているのでこういった変化への対応も必要ですが,なんとなく寂しいと言えば寂しいですね.

OpenNIはオープンソース

Kinectのお使いの方はマイクロソフト社の公式SDKを使いましょう.さて,Xtionの方も単純に光学画像と距離画像を取り込むOpenNIはオープンソースであるため,まだ入手可能です.
OpenNIのgithub(https://github.com/OpenNI/OpenNI)からソースコードを入手できますね!
こちらはなんとか成る...


ですがしかし,Kinectはマイクロソフト公式のSDKを使えばいいとして,Xtion Pro LIVEを使っている自分のような人はどうすればいいんですか???

2014年4月22日火曜日

Qtのproファイルで各OS向けに個別の設定をする

各OS向けQtの.proファイルの設定

Qtの.proファイルでは各OS向けに個別の設定を行うことが出来るみたいですね.クロスプラットフォームで開発する上で,それぞれのOS毎にインクルードパスやライブラリパスを設定できて便利です.

Windows向け

"win32"がWindows向けですね,例によって..
win32 {
# インクルードディレクトリの追加の例
INCLUDEPATH += c:/tbb/include
DEPENDPATH += c:/tbb/include

# ライブラリパスの追加の例(リリースビルド向け)
CONFIG(release, debug|release): LIBS += -Lc:/tbb/lib/intel64/vc10 -ltbb

# ライブラリパスの追加の例(デバッグビルド向け)
CONFIG(debug, debug|release): LIBS += -Lc:/tbb/lib/intel64/vc10 -ltbb_debug
}

Mac向け

Mac OS Xは"macx"と記述します.
macx {
# インクルードディレクトリの追加の例
INCLUDEPATH += /usr/local/Celler/tbb/4.2/include
DEPENDPATH += /usr/local/Celler/tbb/4.2/include

#ライブラリディレクトリの追加の例
LIBS += -L/usr/local/Celler/tbb/4.2/lib -ltbb
}

Unix/Linux向け

UNIXやLinux向けにはやはり"unix"と記述しますが,"unix"だけではMac OS Xでも適用されてしまうようなので,Macを除外するために"unix:!macx"とします
unix:!macx {
# インクルードディレクトリの追加の例
INCLUDEPATH += /usr/include
DEPENDPATH += /usr/include

#ライブラリディレクトリの追加の例
LIBS += -L/usr/lib -lxxxx
}

総括

Qtの.proファイルから各OSの統合開発環境のプロジェクトを作成できたり,makefileを作成できるので,CUIのアプリ開発もC++であればQtの.proファイルを軸に始めると便利だと思います..

2014年4月7日月曜日

QtプロジェクトからVisual StudioやXcodeのプロジェクトを作成

Qt .proファイルからIDEのプロジェクトファイルを作成

QtにはQt Creatorという開発環境があります.Qt Creatorでユーザーインターフェイスのデザインからアルゴリズムコーディングまでの全てを実装することも出来ますが,私は,Qt CreatorでQtプロジェクトの作成と設定のみを行い,その後はWindowsではVisual Studio,MacではXcodeなど使い慣れた統合開発環境で開発を行っています.Qt CreatorではかんたんにQtに関する設定が出来る上,クロスプラットフォームである利点を活かせるからです.

まずはQt CreatorでQtプロジェクトを作成する

.proファイルが作成されていますね.ここで依存ライブラリなどの設定も行います.

インクルードパスを追加 (Windows/Macそれぞれで)

INCLUDEPATHとDEPENDPATHにインクルードするためのディレクトリへのパスを追加します
# Windows向けにincludeディレクトリを追加する例
win32: INCLUDEPATH += C:/OpenCV/opencv-2.4.6/build/x64/vc10/include
win32: DEPENDPATH += C:/OpenCV/opencv-2.4.6/build/x64/vc10/include

# Mac向けに追加する例
macx:INCLUDEPATH += /usr/local/Cellar/opencv/2.4.6.1/include
macx:DEPENDPATH += /usr/local/Cellar/opencv/2.4.6.1/include

依存ライブラリを追加 (Windows/Macそれぞれで)

LIBSに"-Lライブラリのディレクトリへのパス", "-l追加するライブラリファイル"で追加するわけですね.
# Windows向けに追加する例(1行目がリリースモード,2行目がデバッグモード)
win32: CONFIG(release, debug|release): LIBS += -LC:/OpenCV/opencv-2.4.6/build/x64/vc10/lib/ -lopencv_core246 -lopencv_highgui246 -lopencv_imgproc246
else: win32:CONFIG(debug, debug|release): LIBS += -LC:/OpenCV/opencv-2.4.6/build/x64/vc10/lib/ -lopencv_core246d -lopencv_highgui246d -lopencv_imgproc246d

# Mac向けに追加する例
macx: LIBS += -L/usr/local/Cellar/opencv/2.4.6.1/lib/ -lopencv_core -lopencv_highgui -lopencv_imgproc

ビルド時のシンボルを定義

ビルド時のシンボルも定義してみます.
# デバッグビルド時は_Debugを定義する
CONFIG(debug, debug|release): DEFINES += _Debug

Visual Studioのプロジェクトを生成

Qtプロジェクトファイル(.pro)があるディレクトリにて次のコマンドを実行します.
# Visual C++ 2010
$qmake -spec win32-msvc2010 -tp vc

# Visual C++ 2012
$qmake -spec win32-msvc2012 -tp vc

Xcodeプロジェクトを生成

Qtプロジェクトファイル(.pro)があるディレクトリにて次のコマンドを実行します.
$qmake -spec macx-xcode

総括

Qt CreatorでQtプロジェクトの作成・設定を行ってqmakeコマンドを使って各統合開発環境のプロジェクトファイルを作成しました.クロスプラットフォームで使い慣れたツールを使って開発をするときに便利だと感じています.