2013年7月22日月曜日

[訂正]OpenCVを使った緯度経度のGoogleMap上へのプロット

 前回
OpenCVを使った緯度経度のGoogleMap上へのプロット
 で紹介した「2.やり方」よりもっといいやり方があることに気づいたので、投稿しておきます。

前回のやり方では

 A. 緯度経度座標をメルカトル座標に変換する
 B. 取得した地図の中心点と表示させたい点の距離を測って表示する

というやり方をとっていましたが、このやり方だと

  緯度経度座標を直接ピクセル座標(距離情報)に直接変換できない
  つまり、逆変換する時とか、色々めんどくさい仕様になっている

という事に気が付きました。
そこで、緯度経度座標を直接ピクセル座標に変換できる方法を以下のサイト様を参考に(丸パクリ)させて頂き、作ってみました。

参考にさせて頂いたサイト様↓  本当に感謝です!ありがとうございます!!!!m(_ _)m
グーグルマップ(Google Maps) の座標間変換式について(1)

という事で、c言語で書いた変換式を載せておきます。
上のサイトを読まないとよくわからないと思うのでしっかり読んでからご覧ください。


/*========================================================================================
 Name     : real_frame_to_pix_frame
 Argument : point_data *data : 変換するデータ(緯度経度→ピクセル)
            int zoom         : 地図のズームレベル
 Return   : no return
 About    : 緯度経度座標をピクセル座標に変換する
            ポインタにより、データを直接いじるので注意すること
========================================================================================*/
void real_frame_to_pix_frame(point_data *data, int zoom)
{
  (*data).lo = pow(2,7+zoom) * ((*data).lo/180 + 1);

  (*data).la = pow(2,7+zoom)/PI * (-atanh(sin(PI*(*data).la/180)) + atanh(sin(PI*MAX_LA/180)));
}

/*=======================================================================================
 Name     : pix_frame_to_real_frame
 Argument : point_data *data : 変換するデータ(ピクセル→緯度経度)
            int zoom         : 地図のズームレベル
 Return   : no return
 About    : ピクセル座標を緯度経度座標に変換する
       ポインタにより、データを直接いじるので注すること
========================================================================================*/
void pix_frame_to_real_frame(point_data *data, int zoom)
{
  (*data).lo = 180 * ((*data).lo/pow(2,7+zoom) - 1);

  (*data).la = 180/PI * (asin(tanh(-PI*(*data).la/pow(2,7+zoom) + atanh(sin(PI*MAX_LA/180)))));
}

/*=======================================================================================
 Name     : real_frame_to_picture_frame
 Argument : point_data center : 表示する画像の中心緯度経度座標
            point_data data   : 目標点の緯度経度座標
            int zoom          : 地図のズームレベル
 Return   : no return
 About    : 緯度経度座標を画像座標に変換し、
        CvPoint型 picture_frame に格納する
=========================================================================================*/
void real_frame_to_picture_frame(point_data center, point_data data, int zoom)
{
  picture_frame.x = pow(2,7+zoom) * ((data.lo-center.lo)/180);

  picture_frame.y = pow(2,7+zoom)/PI * (-atanh(sin(PI*center.la/180)) + atanh(sin(PI*data.la/180)));
}

/*========================================================================================
 Name     : picture_frame_to_real_frame
 Argument : point_data center : 表示する画像の中心緯度経度座標
            CvPoint data      : 目標点の画像座標
            int zoom          : 地図のズームレベル
 Return   : no return
 About    : 画像座標を緯度経度座標に変換し、
        point_data型 gps に格納する
========================================================================================*/
void picture_frame_to_real_frame(point_data center, CvPoint2D32f data, int zoom)
{
  gps.lo = 180*data.x/pow(2,7+zoom) + center.lo;

  gps.la = 180/PI * asin(tanh(PI*data.y/pow(2,7+zoom) + atanh(sin(PI*center.la/180))));
}

構造体!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 typedef struct {
  double la;  // la is latitude.  緯度
  double lo;  // lo is longitude. 経度
} point_data;

struct CvPoint{
  int x;
  int y;
}

struct CvPoint2D32f{
  float x;
  float y;
}

必要なinclude, define!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#include 
#include 
#include 

#define PI 3.141592653589793
#define MAX_LA 85.0511287798066

コードが見えづらいと思いますので、一応スクショも貼っときます。






以上です。
必要ないことも若干書いてあるので、読みづらいと思いますが、ご勘弁ください。

次は、OpenCVを使って、Googleより取得した地図をくっつけて巨大な地図を作り、その地図の任意の点をクリックするとその点の緯度経度情報を.datファイルに出力するプログラムを作りたいと思います。

それではまた ! ('A')ノシ

2013年7月4日木曜日

OpenCVを使った画像認識による人検出、色検出

今日は(OpenCVを使った)画像認識による人検出、色検出を試してみました。
考え方としては、Webcamからキャプチャした画像(!)を、いわゆるクロマキー合成に似た手順で、指定した色領域のみ切り出し、
更にその処理済みの画像をHaar-likeフィルタで人検出をして矩形領域で確認する
といった感じです。ただ、この方法だとWebcamのキャプチャを1枚1枚取ることになったり、
それをさらに重いHaar-like処理にかけたりするためかなりリソースを食ってしまうのが困りものです。
というか、リアルタイムで処理するのはほぼ不可能に近いレベルです。どうにかして軽く出来ないかと悩んでいます。(i7を積んでいるのにCPUを4割食う)
ハードウェア的にはスイッチや配線類のゴチャゴチャした部分をどうにかしてまとめようと奮闘中です。
将来的にはスイッチ類やモニタ、配線まですべてまとめてシートの下に入れてしまい、人が乗れるようにする
というのが理想ですが……理想です。できたらいいな……
それは置いといて、とりあえず、配線はずいぶんすっきりしました。
プラプラしてたスイッチも一列にまとまってわかりやすくなっています。
こういうの
http://www2.elecom.co.jp/cable/accessory/spiral-tube/index.asp
で配線をクルクルしてまとめる作業は楽しいです。

それでは。

2013年7月3日水曜日

雨雨雨

こんばんは。

ところで、キャンパスは北九州にあるのですが、今日は観測史上最大の大雨が降ったそうで、リバーウォークが真のリバーになったとか、ならなかったとか。
最近は天気に恵まれず、外での実験もできず捗らないです。

今日はロボットがバックできないという致命的な不具合を抱えてしまっていたので、コントローラをiMCs01に変更しました。
コンピュータにインタフェイス社のPCを使っているため、OSが特別にカスタマイズされたものです。なので提供されているドライバがそのままは使えなかったので少しだけソースコードをホゲホゲして使っています。

結果的にバックもできるようになったのでメデタシメデタシ。
それではまたー。

[追加]Gnuplotを使ったボード線図の作成

前回のGnuplotを使ったボード線図の作成では縦軸、横軸の名前、キャプションが適当でこのままでは提出できません。したがって今回はそのタイトルをTeXで流しこむ方法で綺麗にグラフを仕上げようと思います。レポートをTeXで書いている人にはあまり抵抗なくできるのでおすすめです(GnuplotのためだけにTeXを導入するのは結構大変です...)。しかし前回の作成したスクリプトファイル(.plt)を少し修正するだけです。
set terminal epslatex 10
#set terminal postscript eps enhancedをepslatex に、数字の10はフォントサイズ
#カラーで出力したい場合は一行目を"set terminal epslatex color 10"に変更
#保存名を決める
set output "graph1.eps"
#虚数単位jの定義
j={0.0,1.0}
# 伝達関数を定義(今回は一次遅れ系)
G(s)=k/(T*s+1)
#ゲインの定義
k=0.9
#時定数の定義
T=0.5
G1(x)=G(j*x)
set angles degrees
set format x "10^%01T"
#ここで横軸を対数軸に
set logscale x
set xtics nomirror
set ytics nomirror
#ここからゲイン線図の定義
set multiplot
set xlabel '$\omega_{i}$[rad/s]'
#書きたい名前をTeXの文法で書く
set size 1.0,0.6
set origin 0.0,0.4
set ylabel '$20\mathrm{log}_{10}|G(j\omega)|$[dB]'
#横軸の範囲
set xrange [0.1: 20]
#縦軸の範囲
set yrange [-25:5]
plot  20*log10(abs(G1(x))) title "同定結果",\
"graph1.dat" using 1:2 with points pt 7 title "実験結果"
# 日本語もOK
#.datファイルから実験値の読み込み(1:2の1は周波数データ列、2は実際に得られたゲインのデータ列)
#ここから位相線図の定義
set size 1.0,0.4
set origin 0.0,0.0
set ylabel '$\angle G(j\omega)$[deg]'
set ytics 45
# 縦軸の範囲
set yrange [-120:0]
plot arg(G1(x)) title "同定結果",\
"graph1.dat" using 1:3 with points pt 7 title "実験結果"
#1:3の1は周波数データ列、3は実際に得られた位相のデータ列
unset multiplot
set output
set terminal windows
#Mac,Linux の場合、次のように書き換え set terminal x11

修正を行ったら前回と同じように文字コードはEUCにして保存して、スクリプトを実行してください。すると今回はEPSだけでなくTeXファイルも同時に出力されたと思います。これを更に編集します。と言っても、そのTeXファイルの文頭と文末に以下の文を加えるだけです。

文頭に以下の文
\documentclass[a4paper,10pt]{article}
\usepackage{graphicx}
\pagestyle{empty}
\begin{document}
\begin{figure}

文末に以下の文
\end{figure}
\end{document}

文頭の記述
文末の記述
これで保存してください。そしてコマンドプロンプトで
latexmk figure1.tex
dvips figure1.dvi
ps2epsi figure1.ps figure.eps

これらのコマンドを順に叩くだけです。最終的に"figure.eps"が出力されたと思います。

プロット結果
特にボード線図の縦軸のlogや角度記号はTeXで頑張ったかいあって綺麗に出てます(^O^)/今まではグラフの要素だけ作ってinkscapeで一生懸命、日本語や数式を打っていましたが、この方法だとちょっとだけ楽ができます。

最後に今回、latexmkをあえて使ったのはlatexやplatexなどではtexのコンパイルの時点で

! Missing $ inserted.
<inserted text>
        $
l.118    \gplbacktext

のようなエラーが出てしまいdviファイルが出力出来ませんでした。ボード線図自体のスクリプトも結構無理やりな感じがあるのでそれが何か悪さをしているのかもしれません。しかしlatexmkだとエラーは同様に出てしまいますが、dviファイルはそれでも出力してくれたので、暫定的にそうしています。latexmkはWindowsならW32TeX、MacならMacTeXでTeXの環境を入れた人なら一緒に入ってるような気がします。Windowsに関してはPerlを入れなければコマンドが通りませんでした。Perlの環境はStrawberry Perlで動作を確認しました。
http://strawberryperl.com/