2013年8月14日水曜日

ジオコーダー&逆ジオコーダー Google API for Java

緯度・経度と住所の相互変換コード。
GoogleのAPIが便利。後は、LatLngに関係する情報をユーザに返すコードが出来れば、GPSとの連携ができる。


public class GeocoderApp {
public static String invGeocode(double lat, double lng){
final Geocoder geocoder = new Geocoder();
BigDecimal latB = new BigDecimal(lat);
BigDecimal lngB = new BigDecimal(lng);
LatLng location = new LatLng(latB, lngB);
GeocoderRequest geocoderRequest = new GeocoderRequestBuilder().setLocation(location).setLanguage("ja").getGeocoderRequest();
GeocodeResponse geocoderResponse = geocoder.geocode(geocoderRequest);
GeocoderStatus status = geocoderResponse.getStatus();
switch (status) {
case ZERO_RESULTS:
return null;
case OVER_QUERY_LIMIT:
case REQUEST_DENIED:
case INVALID_REQUEST:
case UNKNOWN_ERROR:
case ERROR:
throw new RuntimeException(status.value());
default:
}
List<GeocoderResult> results = geocoderResponse.getResults();
for (GeocoderResult result : results) {
return result.getFormattedAddress();
}
return null;
}
public static LatLng geocode(String address) {
final Geocoder geocoder = new Geocoder();
GeocoderRequest geocoderRequest = new GeocoderRequestBuilder()
.setAddress(address).setLanguage("ja")
.getGeocoderRequest();
GeocodeResponse geocoderResponse = geocoder.geocode(geocoderRequest);
GeocoderStatus status = geocoderResponse.getStatus();
switch (status) {
case ZERO_RESULTS:
return null;
case OVER_QUERY_LIMIT:
case REQUEST_DENIED:
case INVALID_REQUEST:
case UNKNOWN_ERROR:
case ERROR:
throw new RuntimeException(status.value());
default:
}
List<GeocoderResult> results = geocoderResponse.getResults();
for (GeocoderResult result : results) {
GeocoderGeometry geometry = result.getGeometry();
return geometry.getLocation();
}
return null;
}
}

警視庁地域別オープンデータ

人口の地域別データは簡単に手に入るのですが、そのほかで使えるものがあまりありません。
以下が見つけたもの。

 ○警察署別 交通事故発生状況 http://www.keishicho.metro.tokyo.jp/toukei/bunsyo/toukei23/data/kt23_d010.xls

 ○警察署別 刑法犯罪状況 http://www.keishicho.metro.tokyo.jp/toukei/bunsyo/toukei23/data/kt23_d033.xls

 ○警察署別 泥酔者保護(笑) http://www.keishicho.metro.tokyo.jp/toukei/bunsyo/toukei23/data/kt23_d121.xls

 これらはすべて以下のページから取得できます。 警察署別のデータであれば、地域別にデータを分類できそうです。

EC2の起動・停止を費用の削減目的で実施

EC2インスタンスを使わないときは落そう。自動で。
以下の様に簡単にできる。
package jp.masaz.aws;
import java.util.ArrayList;
import java.util.List;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.InstanceState;
import com.amazonaws.services.ec2.model.InstanceStateChange;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StartInstancesResult;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesResult;
/**
* EC2を操作するクラス
*
* @author masahiro
*
*/
public class EC2Tools {
public void startEc2(String intanceId, boolean isDebug) {
try {
if (isDebug) {
System.out.println("start: " + intanceId);
return;
}
BasicAWSCredentials basicAwsCredentials = new BasicAWSCredentials(
AWSConsts.ACCESS_KEY, AWSConsts.SECRET_ACCESS_KEY);
AmazonEC2Client amazonEC2Client = new AmazonEC2Client(
basicAwsCredentials);
amazonEC2Client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
List<String> instanceIds = new ArrayList<String>();
instanceIds.add(intanceId);
StartInstancesRequest startInstancesRequest = new StartInstancesRequest(
instanceIds);
// インスタンスの起動
StartInstancesResult startInstancesResult = amazonEC2Client
.startInstances(startInstancesRequest);
List<InstanceStateChange> stateChanges = startInstancesResult
.getStartingInstances();
List<String> stateList = getResultStatus(stateChanges);
int changeCnt = stateList.size();
System.out.println("start instance cnt: " + changeCnt);
for (String output : stateList) {
System.out.println("start result:" + output);
}
} catch (Exception exception) {
System.out.println("[Error] failed to start ec2 instance: "
+ exception.getMessage());
}
}
public void stopEc2(String intanceId, boolean isDebug) {
try {
if (isDebug) {
System.out.println("stop: " + intanceId);
return;
}
BasicAWSCredentials basicAwsCredentials = new BasicAWSCredentials(
AWSConsts.ACCESS_KEY, AWSConsts.SECRET_ACCESS_KEY);
AmazonEC2Client amazonEC2Client = new AmazonEC2Client(
basicAwsCredentials);
amazonEC2Client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
List<String> instanceIds = new ArrayList<String>();
instanceIds.add(intanceId);
StopInstancesRequest stopInstancesRequest = new StopInstancesRequest(
instanceIds);
// インスタンスの停止
StopInstancesResult stopInstancesResult = amazonEC2Client
.stopInstances(stopInstancesRequest);
List<InstanceStateChange> stateChanges = stopInstancesResult
.getStoppingInstances();
List<String> stateList = getResultStatus(stateChanges);
int changeCnt = stateList.size();
System.out.println("stop instance cnt: " + changeCnt);
for (String output : stateList) {
System.out.println("stop result: " + output);
}
} catch (Exception exception) {
System.out.println("[Error] failed to stop ec2 instance: "
+ exception.getMessage());
}
}
private List<String> getResultStatus(List<InstanceStateChange> stateChanges) {
ArrayList<String> resultList = new ArrayList<String>();
for (InstanceStateChange state : stateChanges) {
String id = state.getInstanceId();
InstanceState pState = state.getPreviousState();
InstanceState cState = state.getCurrentState();
StringBuilder sb = new StringBuilder();
sb.append(id);
sb.append("\t");
sb.append("pState: ");
sb.append(pState.getName());
sb.append(",");
sb.append(pState.getCode());
sb.append("\t");
sb.append("cState: ");
sb.append(cState.getName());
sb.append(",");
sb.append(cState.getCode());
resultList.add(sb.toString());
}
return resultList;
}
}
view raw Ec2Tools.java hosted with ❤ by GitHub

2013年8月13日火曜日

stringはそもそもchar配列

stringはそもそもchar配列という基本を確認。
string line2;
cout << "何か数字を入力してください> " << flush;
getline(cin, line2);
cout << line2 << endl;
const char* line_array = line2.c_str();
const int size = line2.size();
cout << "文字列配列の長さ: " << size << endl;
for(int i = 0; i < size; ++i){
unsigned char c = (unsigned char)line_array[i];
cout << c << endl;
}

Win8 Wi-Fiが不安定なとき

Win8ではハードウェアとの相性のせいか、Wi-Fiが不安定になるときがあります。 デバイスドライバを最新にしましょう。 http://www.intel.com/p/en_US/support/detect/wireless-display

2013年8月4日日曜日

Kinect 距離による表示フィルター RGBと距離カメラの位置補正を含む

距離カメラの情報が1次元データなので、RGBカメラ座標に変換するときに少し工夫する。

#include <iostream>
#include <sstream>
// この順番でインクルード
#include <Windows.h>
#include <NuiApi.h>
#include <opencv2/opencv.hpp>
#define ERROR_CHECK( ret ) \
if ( ret != S_OK ) { \
std::cout << "failed " #ret " " << ret << std::endl; \
exit( 1 ); \
}
const NUI_IMAGE_RESOLUTION CAMERA_RESOLUTION = NUI_IMAGE_RESOLUTION_640x480;
const int MAX_DISTANCE = 300;
class KinectSample{
private:
INuiSensor* kinect;
// RGBカメラ用ハンドル
HANDLE imageStreamHandle;
// 距離カメラ用ハンドル
HANDLE depthStreamHandle;
// RGB及び距離カメラのフレーム更新イベントを待つためのイベントハンドル
HANDLE streamEvent;
DWORD width;
DWORD height;
public:
KinectSample();
~KinectSample();
public:
void initialize();
void run();
private:
void createInstance();
void drawRgbImage(cv::Mat& image);
void drawDepthImage(cv::Mat& image);
};
KinectSample::KinectSample(){
}
// デストラクタ
KinectSample::~KinectSample(){
if(kinect != 0){
// Kinectの終了処理
kinect->NuiShutdown();
// Kinectのインスタンス開放処理
kinect->Release();
}
}
void KinectSample::initialize(){
createInstance();
// RGBカメラ、距離カメラの使用。パイプで区切って設定する。
ERROR_CHECK(kinect->NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH));
/* RGB及び距離カメラをそれぞれ初期化する*/
// RGBカメラ。NUI_IMAGE_TYPE_COLORはRGBカメラの意味。解像度にCAMERA_RESOLUTION、ストリームハンドルのポインタを渡す
ERROR_CHECK(kinect->NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, CAMERA_RESOLUTION, 0,2,0, &imageStreamHandle));
// 距離カメラ
ERROR_CHECK(kinect->NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, CAMERA_RESOLUTION, 0,2,0, &depthStreamHandle));
// フレーム更新イベントのハンドル作成(Win32ApiのCreateEventでハンドラーを作成)
streamEvent = ::CreateEvent(0, TRUE, FALSE, 0);
// kinectオブジェクトにフレーム更新イベントを設定する
ERROR_CHECK(kinect->NuiSetFrameEndEvent(streamEvent, 0));
// 指定解像度の画面サイズを取得
::NuiImageResolutionToSize(CAMERA_RESOLUTION, width, height);
}
void KinectSample::createInstance(){
int count = 0;
// Kinect接続数
ERROR_CHECK(::NuiGetSensorCount(&count));
if(count == 0){
throw std::runtime_error("Kinectを接続してください");
}
// 1台目 インデックス: 0 のキネクトインスタンスを作成
ERROR_CHECK(::NuiCreateSensorByIndex(0, &kinect));
HRESULT status = kinect->NuiStatus();
if(status != S_OK){
throw std::runtime_error("Kinect が利用可能ではありません");
}
}
// RGBカメラの更新されたフレームデータの取得&処理
void KinectSample::drawRgbImage(cv::Mat& image){
NUI_IMAGE_FRAME imageFrame = {0};
// 新しいフレームの取得(runで更新待ちをしているので、待ち時間を 0 にして、すぐに取得する)
ERROR_CHECK(kinect->NuiImageStreamGetNextFrame(imageStreamHandle, 0, &imageFrame));
// フレームの画像データ(更新画像データはpFrameTextureが持っていて、それをLockRectで呼び出してNUI_LOCKED_RECT型で取得する)
NUI_LOCKED_RECT colorData;
imageFrame.pFrameTexture->LockRect(0, &colorData, 0, 0);
// NUI_LOCKED_RECTの画像データをMat型にコピーする。データは1ピクセルあたり、8bitのRGBデータと無効値の4つであり、OpenCVではCV_8UC4と表現する。
// RGBはKinectとOpenCVで共通なので、そのままコピー可能。
image = cv::Mat(height, width, CV_8UC4, colorData.pBits);
// フレームを開放する
ERROR_CHECK(kinect->NuiImageStreamReleaseFrame(imageStreamHandle, &imageFrame));
}
// 距離カメラの更新されたフレームの取得&処理
void KinectSample::drawDepthImage(cv::Mat& image){
NUI_IMAGE_FRAME depthFrame = {0};
// 距離データはピクセル毎に16ビット値として取得することができる。ただし、実際の距離データは16ビットのうち上位13ビット。下位3ビットはプレイヤー認識に使用する。
ERROR_CHECK(kinect->NuiImageStreamGetNextFrame(depthStreamHandle, 0, &depthFrame));
NUI_LOCKED_RECT depthData = {0};
depthFrame.pFrameTexture->LockRect(0, &depthData, 0, 0);
USHORT* depth = (USHORT*)depthData.pBits;
// depthDataは USHORT型の値を持つ。なので、depthDataの要素数はdepthDataのサイズ / USHORTのサイズ。cpp一般の配列と同じ。
for(int i = 0; i < (depthData.size / sizeof(USHORT)); ++i){
// depthDataは16bit値であり、そこから実際の距離を取得するのは、NuiDepthPixelToDepthでできる
USHORT distance = ::NuiDepthPixelToDepth(depth[i]);
// depthは1次元データでheight分格納されている(画像を横に割った状態)。iを擬似的に2次元データに変換する。横幅で割って、余りをx、商をyに割り当てる。
LONG depthX = i % width;
LONG depthY = i / width;
LONG colorX = depthX;
LONG colorY = depthY;
// 引数 : RGB画像解像度、距離画像解像度、
kinect->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(CAMERA_RESOLUTION, CAMERA_RESOLUTION, 0, depthX, depthY, depth[i], &colorX, &colorY);
// 一定以上の距離を表示しない
if(distance >= MAX_DISTANCE){
// CV_8UC4のインデックス
int index = ((colorY * width) + colorX) * 4;
UCHAR* data = &image.data[index];
data[0] = 255;
data[1] = 255;
data[2] = 255;
}
}
// フレームを開放する
ERROR_CHECK(kinect->NuiImageStreamReleaseFrame(depthStreamHandle, &depthFrame));
}
void KinectSample::run(){
cv::Mat image;
while(1){
// イベントハンドルを使って、データの更新を待つ(INFINITEでタイムアウト無し(ずっと待つ))
DWORD ret = ::WaitForSingleObject(streamEvent, INFINITE);
// 更新を受け取ったらリセットする
::ResetEvent(streamEvent);
drawRgbImage(image);
drawDepthImage(image);
cv::imshow("Kinect Sample", image);
int key = cv::waitKey(10);
if(key == 'q'){
break;
}
}
}
void main(){
//Mat a;
try{
KinectSample kinect;
kinect.initialize();
kinect.run();
}catch(std::exception& ex){
std::cout << ex.what() << std::endl;
}
}
view raw DistRGB.cpp hosted with ❤ by GitHub

Kinectでフレームデータの更新を待つ方法

Kinectでフレームデータの更新を待つ方法


  1. INuiSensor::NuiImageStreamGetNextFrame() でタイムアウト値を設定する。
  2. INuiSensor::NuiLimageStreamOpen() に設定したイベントハンドルを使って、WaitForSingleObjectまたはWaitForMultipleObjectsで待つ
  3. INuiSensor::NuiSetFrameEndEvent() に設定したイベントハンドルを使って、WaitForSingleObjectで待つ。
1でタイムアウト値を使う場合は、INFINITE を使うと、タイムアウトを使用せず、ずっと待つようになる。これは、フレーム更新の間に他の処理を行わない場合に使える。もし、フレーム更新の間に他の処理を行う場合は、処理の長さによって、タイムアウトを決定する。




Kinectのインターフェース

Kinectは、以下のNUI ( Natural User Interface ) インターフェースを備えます。

何をしたいかで、どれを使えば良いかおおまかにわかります。

Natural User Interface


INuiSensor : Kinectセンサーのハードウェアアクセス機能を提供
INuiFrameTexture : RGB及び距離カメラのピクセルデータを取得


音声

INuiAudioBeam : 音源方向を取得する。QueryInterface()で音声入力や、設定プロパティへのアクセス機能を取得できる。

INui~とNui~

INuiはKinectを複数用いる。Nuiは1台。どちらも同じ関数、機能を提供する。


Kinectアプリケーションビルド時の注意点

Kinectアプリケーションは、x86アプリなのか、x64アプリなのか、明確にした上で環境設定を行うこと。

そうしないと、以下のエラーでビルドに失敗する。

fatal error LNK1112: モジュールのコンピューターの種類 ‘X64′ は対象コンピューターの種類 ‘x86′ と競合しています。

これは、x86のアプリで、x64のライブラリを使おうとする場合におこる。
逆の場合もありえる。
C++のWin32コンソールアプリを選んだ場合、KinectとOpenCVのライブラリを x86 で統一しておくと安全。

Kinect Basic Sample 01 RGB Camera View

Kinectを使って身体の研究をするプロジェクトの第一弾。 最も簡単なSample。 RGBカメラの表示。
#include <iostream>
#include <sstream>
// この順番でインクルード
#include <Windows.h>
#include <NuiApi.h>
#include <opencv2/opencv.hpp>
#define ERROR_CHECK( ret ) \
if ( ret != S_OK ) { \
std::cout << "failed " #ret " " << ret << std::endl; \
exit( 1 ); \
}
const NUI_IMAGE_RESOLUTION CAMERA_RESOLUTION = NUI_IMAGE_RESOLUTION_640x480;
class KinectSample{
private:
INuiSensor* kinect;
HANDLE imageStreamHandle;
DWORD width;
DWORD height;
public:
KinectSample();
~KinectSample();
public:
void initialize();
void run();
private:
void createInstance();
void drawRgbImage(cv::Mat& image);
};
KinectSample::KinectSample(){
}
// デストラクタ
KinectSample::~KinectSample(){
if(kinect != 0){
// Kinectの終了処理
kinect->NuiShutdown();
// Kinectのインスタンス開放処理
kinect->Release();
}
}
void KinectSample::initialize(){
createInstance();
// RGBカメラの使用
ERROR_CHECK(kinect->NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR));
//NUI_IMAGE_TYPE_COLORはRGBカメラの意味。解像度にCAMERA_RESOLUTION、ストリームハンドルのポインタを渡す
ERROR_CHECK(kinect->NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, CAMERA_RESOLUTION, 0,2,0, &imageStreamHandle));
// 指定解像度の画面サイズを取得
::NuiImageResolutionToSize(CAMERA_RESOLUTION, width, height);
}
void KinectSample::run(){
cv::Mat image;
while(1){
drawRgbImage(image);
cv::imshow("Kinect Sample", image);
int key = cv::waitKey(10);
if(key == 'q'){
break;
}
}
}
void KinectSample::createInstance(){
int count = 0;
// Kinect接続数
ERROR_CHECK(::NuiGetSensorCount(&count));
if(count == 0){
throw std::runtime_error("Kinectを接続してください");
}
// 1台目 インデックス: 0 のキネクトインスタンスを作成
ERROR_CHECK(::NuiCreateSensorByIndex(0, &kinect));
HRESULT status = kinect->NuiStatus();
if(status != S_OK){
throw std::runtime_error("Kinect が利用可能ではありません");
}
}
// 更新されたフレームデータの取得&処理
void KinectSample::drawRgbImage(cv::Mat& image){
NUI_IMAGE_FRAME imageFrame = {0};
// 新しいフレームの取得(INFINETE タイムアウト無し(フレーム更新間に処理無し))
ERROR_CHECK(kinect->NuiImageStreamGetNextFrame(imageStreamHandle, INFINITE, &imageFrame));
// フレームの画像データ(更新画像データはpFrameTextureが持っていて、それをLockRectで呼び出してNUI_LOCKED_RECT型で取得する)
NUI_LOCKED_RECT colorData;
imageFrame.pFrameTexture->LockRect(0, &colorData, 0, 0);
// NUI_LOCKED_RECTの画像データをMat型にコピーする。データは1ピクセルあたり、8bitのRGBデータと無効値の4つであり、OpenCVではCV_8UC4と表現する。
// RGBはKinectとOpenCVで共通なので、そのままコピー可能。
image = cv::Mat(height, width, CV_8UC4, colorData.pBits);
// フレームを開放する
ERROR_CHECK(kinect->NuiImageStreamReleaseFrame(imageStreamHandle, &imageFrame));
}
void main(){
//Mat a;
try{
KinectSample kinect;
kinect.initialize();
kinect.run();
}catch(std::exception& ex){
std::cout << ex.what() << std::endl;
}
}

2013年8月3日土曜日

Cpp VC++ で std::copy を使おうとすると C4996エラーになるので回避

以下のコードで回避。
template<class II, class OI> inline OI std_copy(II in, II end, OI out) {
for (; in != end; ++in, ++out) *out = *in;
return out;
}
int main() {
int a [] = {1, 2, 3};
int b [] = {4, 5, 6};
std_copy(a, a + 3, b);
}
view raw gistfile1.cpp hosted with ❤ by GitHub