Exemple #1
0
int main(int argc, char **argv)
{
	lasttime = time(NULL);
	if(argc < 3)
   {
      printf("Usage : %s [address] [name] [port]\n", argv[0]);
      return EXIT_FAILURE;
   }
	//first send the application name
	sock = init_connection_module(argv[1],atoi(argv[3]));
	char buffer[BUF_SIZE];
	//use of a descriptor in order to use non-blocking sockets
	fd_set rdfs;
	if(fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
		printf("Error setting socket in non blocking mode\n");
	else
		printf("Socket is in non blocking mode\n");

	// send the Applcation's name
	write_server(sock, argv[2]);
	write_server(sock, createInitGestureXml().c_str());
	XnStatus retVal = XN_STATUS_OK;

	//context creation
	Context context;

	//depth generator
	DepthGenerator depth;

	//for the led
	XN_USB_DEV_HANDLE usbHandle;
	bool foundUsb = false;
	const XnUSBConnectionString *paths;
    XnUInt32 count;
	//for tracking the user
	XnSkeletonJointPosition pos1, pos2;

	retVal = xnUSBInit();
	//retVal = 0;
	if (retVal != XN_STATUS_OK)
    {
        xnPrintError(retVal, "xnUSBInit failed");        
    }
	else
		retVal = xnUSBEnumerateDevices(0x045E /* VendorID */, 0x02B0 /*ProductID*/, &paths, &count);
    if (retVal != XN_STATUS_OK)
    {
        xnPrintError(retVal, "xnUSBEnumerateDevices failed");        
    }else
	{
		retVal = xnUSBOpenDeviceByPath(paths[0], &usbHandle);
		foundUsb = true;
	}


	//sessiong manager - NITE
	XnVSessionManager* pSessionGenerator;

	//context init
	retVal = context.Init();

	retVal = g_GestureGenerator.Create(context); 
	retVal = g_HandsGenerator.Create(context);
	retVal = depth.Create(context);
	
	pSessionGenerator = new XnVSessionManager();
	pSessionGenerator->Initialize(&context, "Wave", "RaiseHand");

	//start generating data
	retVal = context.StartGeneratingAll();

	/* session callbacks - START = when we detect focus or short focus gesture;
						   STOP = when we loose track;
						   PROGRESS = when we're interacting;
	*/
	pSessionGenerator->RegisterSession(NULL, &SessionStart, &SessionEnd, &SessionProgress);

	//swipe control
	XnVSwipeDetector sw;
	sw.RegisterSwipeLeft(NULL, swipeLeft);
	sw.RegisterSwipeRight(NULL, swipeRight);
	pSessionGenerator->AddListener(&sw);
	XnVPushDetector pw;
	pw.RegisterPush(NULL, push);
	pSessionGenerator->AddListener(&pw);
	XnVSteadyDetector st;
	st.RegisterSteady(NULL, steady);
	//pSessionGenerator->AddListener(&st);

	while(true)
	{

		//wait for data to be ready on depth node and update all nodes;		
		retVal = context.WaitAnyUpdateAll();		
		if(retVal != XN_STATUS_OK)
		{			
			cout << "failed updating data; reason: " << xnGetStatusString(retVal) << endl;
			continue;
		}
		pSessionGenerator->Update(&context);

		//network
		resetDescriptor(&sock, &rdfs);
		int n = read_server(sock, buffer);
		if(n > 0)
		  printf("################## Received from server: %s ##############\n", buffer);
	}
		
	

end_connection_module(sock);
context.Release();
delete pSessionGenerator;
	system("PAUSE");

	return EXIT_SUCCESS;
}
Exemple #2
0
////////////////////
// main
////////////////////
int main (int argc, char* const argv[]) {
    
    int count = 0;
    
    //客寄せアプリか
    bool bAttractApl = ATTRACT_APL;
    
    // 輪郭の表示・非表示フラグ、輪郭保存リスト
    bool bShowOutline = 0;
    std::vector<IplImage *> outlineImageList;
    
    // 過去のユーザ画像の表示・非表示フラグ
    bool bShowPastUser = 1;
    
    // カメラ画像の表示・非表示フラグ
    bool bShowImage = 0;
    
    // ログを表示するか
    bool bShowLog = SHOW_LOG;
    
    // バタフライ表示
    bool bShowButtefly = 1;
    
    // 現在のユーザを表示
    bool bShowCurrentUser = 1;
    
    // ユーザ画像を変化させるか
    bool bChangeUserImage = 0;
    
    // 背景を切り替え中か
    bool bTransBackground = 0;
    
    // 背景をスクロール切り替え中か
    bool bScrollBackground = 0;
    
    // 両手をあわせるチェック中か
    int iCheckFallonBothhand = 0;
    
    // 両目を隠し中か
    int iCheckHideEyes = 0;

    int startCount = 0;
    int endCount = 0;
    IplImage *initImage;
    IplImage *endImage;
    IplImage *scrollImage;
    
    // 過去のユーザ数
    int pastUsers = 0;
    
    // 撮影する時間
    int filmCount = -1;
    
    // 撮影した回数
    int filmSum = 0;
    
    // キャラクター番号
    int chara_num = 0;
    
    // 背景
    std::vector<BgElement> bgList;
    
    // Tilt
    int angle = 0;
    XnUChar empty[0x1];
	
	xn::Context context;
	
    srand( time(NULL));
    //ユーザのハッシュ番号を表示
    if( GET_USERNAME){
       // chara_num = getHash( getUserName(dir_path)) % CHARA_COUNT; // ハッシュで行う場合 
        chara_num = rand() % CHARA_COUNT; //ランダムで行う場合
        std::cout << "ハッシュ番号 = " << chara_num << endl;
    }
    
    cvInitFont(&jointFont, CV_FONT_HERSHEY_SIMPLEX , 0.2, 0.2, 0.0, 1, CV_AA);	
	cvInitFont(&calibFont, CV_FONT_HERSHEY_SIMPLEX , 0.3, 0.3, 0.0, 1, CV_AA);	
	
	try {
        ///////////////////////////////////////////////////////////////////
		// OpenNIコンテキストの作成
		xn::EnumerationErrors ctxErrors;
        XnStatus rc;
        
		rc = context.InitFromXmlFile(CONFIG_XML_PATH, &ctxErrors);
		if (rc != XN_STATUS_OK) {
			XnChar strError[1024];
			ctxErrors.ToString(strError, 1024);
			throw std::runtime_error(strError);
		}
#ifdef DEBUG_PLAYRECORD
        //記録した深度情報を再生
        //xn::Player player;
        context.OpenFileRecording( RECORD_FILE_PATH);
        
#endif
		context.SetGlobalMirror(true);
        
        
        // ImageGeneratorの生成
        xn::ImageGenerator image;
        rc = context.FindExistingNode(XN_NODE_TYPE_IMAGE, image);
        errorCheck(rc);
        
		// DepthGeneratorの取得
		xn::DepthGenerator depth;
		rc = context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);
		errorCheck(rc);
        
		// UserGeneratorの取得
		xn::UserGenerator user;
		rc = context.FindExistingNode(XN_NODE_TYPE_USER, user);
		errorCheck(rc);
		
		// cookieの作成
		XnChar pose[20] = "";
		CalibrationCookie cookie = {&user, &depth, JUST_GENERATED, pose, &bAttractApl};
		
		// コールバックの登録
		XnCallbackHandle userCallbacks, poseCallbacks, calibCallbacks;
		user.RegisterUserCallbacks(NewUser, LostUser, &cookie, userCallbacks);
		
		// PoseCapabilityの取得
		xn::PoseDetectionCapability poseCap = user.GetPoseDetectionCap();
		poseCap.RegisterToPoseCallbacks(&DetectedPose, &LostPose, &cookie, poseCallbacks);
        
		// SkeletonCapabilityの取得
		xn::SkeletonCapability skeletonCap = user.GetSkeletonCap();
		skeletonCap.GetCalibrationPose(pose);
		skeletonCap.RegisterCalibrationCallbacks(&StartCalibration, &EndCalibration, &cookie, calibCallbacks);
		skeletonCap.SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
		
		// 表示用の画像データの作成
		XnMapOutputMode mapMode;
		depth.GetMapOutputMode(mapMode);
		rgbImage = cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
        
        ///////////////////////////////////////////////////////////////////        
        
		// ユーザの画像
        userImage = cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
        pastUserImage = cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
        cvSetZero(pastUserImage);
        
        std::cout << "Initialize Start" << std::endl;
        
        initImage =  cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
        endImage =  cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
        
        scrollImage = cvCreateImage(cvSize(mapMode.nXRes*2, mapMode.nYRes), IPL_DEPTH_8U, 3);
        
        //NITEを使用するか
        #ifdef DEBUG_NITE
            // NITEのセッション初期化
            XnVSessionManager sessionManager;
            rc = sessionManager.Initialize(&context, 
                                            "Wave,Click", 
                                            "RaiseHand");
            if (rc != XN_STATUS_OK) {
                throw std::runtime_error(xnGetStatusString(rc));
            }
            
            // セッションの開始終了時のコールバックの登録
            XnVHandle sessionCallback = 
            sessionManager.RegisterSession(0, 
                                            &SessionStart, 
                                            &SessionEnd);
            
            
            // 検出器の作成
            XnVSwipeDetector swipeDetector;
            // 検出する最低速度(デフォルトは 0.25m/s)
            swipeDetector.SetMotionSpeedThreshold(0.1);
            // 検出する最低持続時間 (デフォルトは350ms)
            swipeDetector.SetMotionTime(100);
            // X軸方向からのずれの許容角度 (デフォルトは25度)
            swipeDetector.SetXAngleThreshold(35);
            
            // スワイプ検出時のコールバックを登録
            XnCallbackHandle swipeRightCallback = swipeDetector.RegisterSwipeRight((void*)"Right", Swipe);
            XnCallbackHandle swipeLeftCallback = swipeDetector.RegisterSwipeLeft((void*)"Left", Swipe);
            
            // セッションに検出器を登録
            sessionManager.AddListener(&swipeDetector);
            
            // Push操作のコールバック引数の登録 Push操作で背景を変化させるため
            argsChangeBg* cb = new argsChangeBg();
            cb->bgImage = &bgImage;
            cb->backnum = &backnum;
            cb->dir_path = dir_path;
        
            // Push 前後運動の検出
            XnVPushDetector pushDetector;
            XnCallbackHandle pushCallback = pushDetector.RegisterPush((void *)cb, Push);
            XnCallbackHandle stabilizedCallback = pushDetector.RegisterStabilized(0, Stabilized);
            
            sessionManager.AddListener(&pushDetector);
            
            // ジェスチャー認識の開始
            context.StartGeneratingAll();
        #endif

        
        //ユーザ移動の記録機能を使用するか
        #ifdef DEBUG_RECORD
            xn::Recorder recorder;
            check(recorder.Create(context));
        
            //保存設定
            check(recorder.SetDestination(XN_RECORD_MEDIUM_FILE, RECORD_FILE_PATH));
        
            //カメラ画像を記録開始
            check(recorder.AddNodeToRecording(image, XN_CODEC_JPEG));
            
            //深度情報を記録開始
            check(recorder.AddNodeToRecording(depth, XN_CODEC_UNCOMPRESSED));
            
            //ユーザ情報を記録開始
           // check(recorder.AddNodeToRecording(user, XN_CODEC_NULL));
        
            std::cout << "Start Recording .." << std::endl;
            check(recorder.Record());
        #endif
        
        
        
        std::cout << "Initialize Success" << std::endl;
        
        //画像リストのインデックスを乱数でセット
        srand((unsigned)time(NULL));
        imageIndex = rand() % 77; 
		
        // キャリブレーション時の画像をあらかじめ読み込み
        // 読み込んだ画像はpartsImageMapに格納される
        loadPartsImage( &partsImageMap, chara_num, dir_path);
        
     
        //背景画像貼付け
        changeBackground( &bgImage, &backnum, dir_path);
        
        // ループ
		while(1) {
            
            //セッション更新
            #ifdef DEBUG_NITE
                sessionManager.Update(&context);   
            #endif
            
			// ノードの更新を待つ
            
            if( bAttractApl != 0){
                context.WaitAndUpdateAll();
            }else{
                // デモアプリはユーザの更新情報のみ取得する
                /*if(pastUsers > 2){
                    sleep(10);
                    pastUsers = 1;
                }*/
                user.WaitAndUpdateData();
            }
                
			cvZero(rgbImage);
            
        
            
            //背景がトランジション中か
            if( bTransBackground){
                if( transBackground( initImage, endImage, bgImage , startCount, endCount, count)){
                    bTransBackground = 0;
                    startChangeBackground( scrollImage, bgImage, initImage,  &endImage, &backnum, &bTransBackground, &bScrollBackground, &startCount, &endCount, count, dir_path , &bgList);            
                    std::cout << "trans background end " <<  count <<endl;
                }

            }
            
            // 背景がスクロール中か
            if( bScrollBackground){
                if( scrollBackground( scrollImage, bgImage, startCount, endCount, count )){
                    bScrollBackground = 0;
                    startChangeBackground( scrollImage, bgImage, initImage,  &endImage, &backnum, &bTransBackground, &bScrollBackground, &startCount, &endCount, count, dir_path , &bgList);            
                    std::cout << "scroll background end " <<  count <<endl;
                }

            }
            
            cvCopy( bgImage, rgbImage);
            
			// UserGeneratorからユーザー識別ピクセルを取得
			xn::SceneMetaData sceneMetaData;
			user.GetUserPixels(0, sceneMetaData);
            
            // ユーザー画像書き込み
            cvSetZero(userImage);
            
			int pos = 0;
			for (int y=0; y<sceneMetaData.YRes(); y++) {
				for (int x=0; x<sceneMetaData.XRes(); x++) {
					XnLabel label = sceneMetaData(x, y);
					
					
					if (label > 0) {
						// 適当な色を付ける、マスク画像の関係で画素の値を修正
						userImage->imageData[pos+0] = label%2 == 0 ? 1 : 255;
						userImage->imageData[pos+1] = label%2 == 0 ? 255 : 1;
						userImage->imageData[pos+2] = label%3 == 0 ? 255 : 1;
					}
					pos += 3;
                    
					
				}
			}
            
            // ユーザ画像を変化させる
            if( bChangeUserImage){
                changeUserImage( userImage, 0, count);
          
            }
            
            
         
            
            if( bShowPastUser) {
                // ユーザの画像を定期的にキャプチャし、保持する
                captureUserImage( &pastImageList, userImage, pastUserImage, count);
            
                // ユーザの過去の画像を現在の画像に重ね合わせる
                fallPartImage(pastUserImage, rgbImage);
            }
            
            // 輪郭を表示
            showOutlineBody(&outlineImageList, rgbImage, bShowOutline);
            
               
            // 現在のユーザの画像を重ね合わせる
            if( bShowCurrentUser){
                fallPartImage(userImage, rgbImage);
            }
            
            
            
            // イメージを表示
            if( bShowImage){
                xn::ImageMetaData imageMetaData;
                image.GetMetaData( imageMetaData);
                
                IplImage* photoImage = cvCreateImage(cvSize(mapMode.nXRes, mapMode.nYRes), IPL_DEPTH_8U, 3);
                xnOSMemCopy(photoImage->imageData, imageMetaData.RGB24Data(), rgbImage->imageSize);
                
                double alpha = ADD_IMAGE_ALPHA;
                
                cvAddWeighted(photoImage, alpha, rgbImage, 1.0-alpha, 0.0, rgbImage);
                //cvAdd(photoImage, rgbImage, rgbImage);
                
                cvReleaseImage(&photoImage);
                
            }
            
            
            // ユーザ表示をする
            if( bShowCurrentUser == 0){
                changeOnOffBoolean( &bShowCurrentUser);
            }
            
            // 過去のユーザ表示をする
            if( bShowPastUser == 0){
                changeOnOffBoolean( &bShowPastUser);
            }
			
			//XnUserID allUsers[20];
			XnUserID allUsers[3];
			//XnUInt16 nUsers = 20;
			XnUInt16 nUsers = 3;
			user.GetUsers(allUsers, nUsers);
            
            XnUInt16 userNums = user.GetNumberOfUsers();
            
            if( bAttractApl != 0){
            
			for (int i = 0; i < nUsers; i++) {
                //std::cout << " i = " <<  i << ", isTracking No = " << allUsers[i] << endl;
				// キャリブレーションに成功しているかどうか
				if (skeletonCap.IsTracking(allUsers[i])) {
                    
					// 各ジョイント情報の描画
					XnUserID u = allUsers[i];
                    

                    // 画像を表示
                    if( bChangeUserImage == 0){                        
                        drawTorso(depth, skeletonCap, u, mapMode, partsImageMap["torso"], &rgbImage);
                        drawHead(depth, skeletonCap, u, mapMode, partsImageMap["head"], &rgbImage); 
                        drawRightArm(depth, skeletonCap, u, mapMode, partsImageMap["right_arm"], &rgbImage);
                        drawRightForearm(depth, skeletonCap, u, mapMode, partsImageMap["right_forearm"], &rgbImage);
                        drawLeftArm(depth, skeletonCap, u, mapMode, partsImageMap["left_arm"], &rgbImage);
                        drawLeftForearm(depth, skeletonCap, u, mapMode, partsImageMap["left_forearm"], &rgbImage);
                        
                    }
                        
                    // 腕のクロス判定
                    if( checkCrossHand( depth, skeletonCap, u, XN_SKEL_LEFT_ELBOW, XN_SKEL_LEFT_HAND, XN_SKEL_RIGHT_ELBOW, XN_SKEL_RIGHT_HAND)){
                        std::cout << "cross hand" <<endl;
                        // 天使の場合、チョウチョを発生させる
                        if( chara_num == 0 || CHARA_ALL == 1){
                            do_fly_butterfly(rgbImage, count);
                        }

                    }
                    
                    // 両手・両腕が前に出ているかの判定
                    if( checkStraightenArms( depth, skeletonCap, u, 
                                            XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_ELBOW, XN_SKEL_LEFT_HAND, XN_SKEL_RIGHT_SHOULDER, XN_SKEL_RIGHT_ELBOW, XN_SKEL_RIGHT_HAND)){

                        std::cout << "straight arms" <<endl;
                        //背景連続スクロール
                        if( bScrollBackground == 0){
                            if ( chara_num == 1 || CHARA_ALL == 1) {
                                continueChangeBackground(&bgList, &backnum, dir_path);
                                
                                startChangeBackground( scrollImage, bgImage, initImage, &endImage, &backnum, &bTransBackground, &bScrollBackground, &startCount, &endCount, count, dir_path , &bgList);
                                
                                
                            }
                        }
                    }
                    
                    // 手の重なり判定
                    if( checkFallonBothhand( depth, skeletonCap, u, XN_SKEL_LEFT_HAND, XN_SKEL_RIGHT_HAND)){
                        if( iCheckFallonBothhand > FALLON_BOTHHAND_TIME ){
                            //手がFALLON_BOTHHAND_TIMEより長く重なっていたため、何らかの処理を実行する
                            
                            
                            // 魔術師の場合、ユーザを細くする
                            if( chara_num == 3 || CHARA_ALL == 1){
                                
                                changeOnOffBoolean( &bChangeUserImage);
                                
                                iCheckFallonBothhand = 0;
                                iCheckHideEyes = 0;
                            }
                        }else{
                            iCheckFallonBothhand++;
                        }
                        
                    }else{
                        //一回でも手が重ならなくなったら、カウントは0に戻る
                        iCheckFallonBothhand = 0;
                    }
                   
					
                    // ユーザ表示を消す
                    if( bShowCurrentUser == 1 && bChangeUserImage == 0){
                        changeOnOffBoolean( &bShowCurrentUser);
                    }
                    
                    // 過去のユーザ表示を消す
                    if( bShowPastUser == 1 && bChangeUserImage == 0){
                        changeOnOffBoolean( &bShowPastUser);
                    }
                    
                    // 右手挙げ判定
                    if( checkRaiseRightHand( depth, skeletonCap, u, XN_SKEL_RIGHT_HAND, XN_SKEL_RIGHT_ELBOW, XN_SKEL_RIGHT_SHOULDER, XN_SKEL_HEAD)){
                        std::cout << "raise right hand" <<endl;
                        flashRightHand(rgbImage, count, depth, skeletonCap, u);
                    }
                    
                    if( checkHideEyes( depth, skeletonCap, u, XN_SKEL_HEAD, XN_SKEL_LEFT_HAND, XN_SKEL_RIGHT_HAND)){
                        if( iCheckHideEyes > HIDE_EYES_TIME ){
                            //手がHIDE_EYES_TIMEより長く重なっていたため、何らかの処理を実行する
                            
                            // キャラ切り替え
                            chara_num = ( chara_num + 1) % CHARA_COUNT;
                            
                            partsImageMap.clear();
                            loadPartsImage( &partsImageMap, chara_num, dir_path);
                            iCheckHideEyes = 0;
                            iCheckFallonBothhand = 0;

                        }else{
                            iCheckHideEyes++;

                        }
                    }
                    
					// 最初の一人だけ処理したら抜ける
					break;
				}
			}
            
			// 現在のキャリブレーション状況
			std::string strStatus;
			CALIBRATION_STATUS status = cookie.lastStatus;
			if (status == JUST_GENERATED) {
				strStatus = "Just Generated";
			} else if (status == USER_DETECTED) {
				strStatus = "User Detected";
			} else if (status == USER_LOST) {
				strStatus = "User Lost";
			} else if (status == POSE_DETECTED) {
				strStatus = "Pose Detected";
			} else if (status == POSE_LOST) {
				strStatus = "Pose Lost";
			} else if (status == CALIB_STARTED) {
				strStatus = "Calibration Started";
			} else if (status == CALIB_SUCCEEDED) {
				strStatus = "Tracking Started";
			} else {
				strStatus = "Calibration Failed";
			}
			// counter
            char numstr[1000];
            sprintf(numstr, "%d", count);
            strStatus += numstr;
            
            if(bShowLog){
                cvPutText(rgbImage, strStatus.c_str(), cvPoint(500, 10), &calibFont, CV_RGB(255, 255, 255));
            }
                
            }else{
                //客寄せアプリ用
                
                if( pastUsers < userNums ){
                    // 客が増えたとき、撮影時間を指定する
                    filmCount = count + 20;
                    std::cout << " userNums Increment count = " << count << " , userNums = " << userNums <<endl;
                    
                }else if( pastUsers > userNums){
                    std::cout << " userNums Decrement count = " << count << " , userNums = " << userNums <<endl;
                }
                
                if( filmCount == count){
                    // 撮影時間
                    
                    // 輪郭を保存
                    std::cout << "film outline save" <<endl;
                    saveOutlineBody( &outlineImageList, userImage, 1, &filmSum);
                    
                    // 背景をスクロールで切り替え
                    initScrollBackground( scrollImage, bgImage, endImage, &backnum, &bScrollBackground, &startCount, &endCount, count, dir_path);
                    
                }
                
                // pastUserを表示する
                if( !bShowOutline){
                    changeOnOffBoolean( &bShowOutline);
                }
                
                // 客のユーザ
                pastUsers = userNums;
                
              //  usleep(100000);
                
            }
            
                
                
            // 表示
			cvShowImage("User View", rgbImage);
            count++;
            
            /**
             * Key Command
             * ESC, q : end
             * u : チルトup
             * d : チルトdown
             * s : チルト初期位置
             * 
             * p : 輪郭を取得・表示
             * a : 現在画面に表示されている画像を保存
             *
             * i : カメラ画像を半合成
             * k : バタフライを表示・非表示きりかえ
             * j : ユーザの表示・非表示きりかえ
             * o : 輪郭の表示・非表示きりかえ
             * l : 過去のユーザの履歴表示・非表示きりかえ
             * 
             * b : 背景きりかえ
             * n : 背景トランジション切り替え
             * m : 背景スクロール切り替え
             * v : 背景連続スクロール
             * y : ユーザイメージ切り替え
             *
             * x : ログを表示するか
             * z : 客寄せアプリ切り替え
             */
			char key = cvWaitKey(10);
			if (key == 27 || key == 'q') {
				break;
			}
            
            // Tilt
            else if (key == 's'){
                angle = 0;
                
                rc = xnUSBOpenDevice(VID_MICROSOFT, PID_NUI_MOTOR, NULL, NULL, &dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBSendControl(dev, XN_USB_CONTROL_TYPE_VENDOR, 0x31, (XnUInt16)angle, 0x0, empty, 0x0, 0);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBCloseDevice(dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
            }
            else if (key == 'u'){
                angle += 5;
                
                rc = xnUSBOpenDevice(VID_MICROSOFT, PID_NUI_MOTOR, NULL, NULL, &dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBSendControl(dev, XN_USB_CONTROL_TYPE_VENDOR, 0x31, (XnUInt16)angle, 0x0, empty, 0x0, 0);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBCloseDevice(dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
            }
            else if (key == 'd'){
                angle -= 5;
                
                rc = xnUSBOpenDevice(VID_MICROSOFT, PID_NUI_MOTOR, NULL, NULL, &dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBSendControl(dev, XN_USB_CONTROL_TYPE_VENDOR, 0x31, (XnUInt16)angle, 0x0, empty, 0x0, 0);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
                
                rc = xnUSBCloseDevice(dev);
                if (rc != XN_STATUS_OK) {
                    throw std::runtime_error(xnGetStatusString(rc));
                }
            }
            else if (key == 'c'){
               // cvReleaseImage(&partImage);
               // imageIndex = rand() % 77;
                chara_num = ( chara_num + 1) % CHARA_COUNT;
                
                partsImageMap.clear();
                loadPartsImage( &partsImageMap, chara_num, dir_path);
            }
            else if (key == 'b') {
                changeBackground( &bgImage, &backnum, dir_path);
                
            }
            else if(key == 'p') {
                // 輪郭を保存
                std::cout << "push button p. outline save" <<endl;
                saveOutlineBody( &outlineImageList, userImage);

            }   
            else if(key == 'o') {
                // 輪郭を表示・非表示きりかえ
                std::cout << "push button o. outline showChange" <<endl;
                changeOnOffBoolean( &bShowOutline);
            }else if(key == 'l'){
                changeOnOffBoolean( &bShowPastUser);
            }
            else if(key == 'a'){
                // 現在の画像をファイルに保存
                const char* saveFilename = ( dir_path + "saveImage/" + "image" + getCurrentTime() + ".png" ).c_str();
                cvSaveImage(saveFilename, rgbImage);
                
            }
            else if(key == 'i'){
                // カメラ画像を表示画像に合成
                changeOnOffBoolean( &bShowImage);
                
            }else if(key == 'k'){
                // バタフライ表示の切り替え
                changeOnOffBoolean( &bShowButtefly);
            }else if(key == 'j'){
                // 現在のユーザ表示の切り替え
                changeOnOffBoolean( &bShowCurrentUser);
            }else if(key == 'n'){
                // 背景とトランジションで切り替え
                initTransBackground( initImage, &endImage, bgImage, &backnum, &bTransBackground, &startCount,  &endCount, count, dir_path);
            }else if(key == 'm'){
                // 背景をスクロールで切り替え
                initScrollBackground( scrollImage, bgImage, endImage, &backnum, &bScrollBackground, &startCount, &endCount, count, dir_path);
                
            }else if(key == 'v'){
                // 背景を連続で切り替え
                continueChangeBackground(&bgList, &backnum, dir_path);
                startChangeBackground( scrollImage, bgImage, initImage, &endImage, &backnum, &bTransBackground, &bScrollBackground, &startCount, &endCount, count, dir_path , &bgList);
            }else if(key == 'y'){
                // ユーザ表示を細くする
                changeOnOffBoolean( &bChangeUserImage);
                
            }else if(key == 'x'){
                // ログを表示するか
                changeOnOffBoolean( &bShowLog);
            }else if(key == 'z'){
                if ( bAttractApl) {
                    // 通常アプリが動いている場合、ポーズ検出を停止する
                    int userNums = user.GetNumberOfUsers(); 
                    XnUserID allUsers[userNums];
                    XnUInt16 nUsers = userNums;
                    
                    user.GetUsers(allUsers, nUsers);
                    //客寄せアプリが動いている場合、ポーズ検出を開始させる
                    for( int i=0; i<userNums; i++){
                        std::cout << "user stopPose ID = " << i << endl;
                        user.GetPoseDetectionCap().StopPoseDetection( (XnUserID)i);
                    }
                }else{
                    //客寄せアプリが動いている場合、ポーズ検出を開始させる
                    int userNums = user.GetNumberOfUsers(); 
                    XnUserID allUsers[userNums];
                    XnUInt16 nUsers = userNums;

                    user.GetUsers(allUsers, nUsers);

                    for( int i=0; i<userNums; i++){
                        std::cout << "user startPose ID = " <<  allUsers[i] << endl;
                        user.GetPoseDetectionCap().StartPoseDetection( pose, allUsers[i]);
                    }
                }
                
                
                // 客寄せアプリの切り替え
                changeOnOffBoolean( &bAttractApl);
                
                if(bShowOutline){
                    changeOnOffBoolean(&bShowOutline);
                }
                std::cout << "アプリきりかえ、bAttractAplが1だと、キャリブレーション実行。 bAttractApl = " << bAttractApl << endl;
            }
            
		}
        


        // 登録したコールバックの解除
#ifdef DEBUG_NITE
            swipeDetector.UnregisterSwipeRight(swipeRightCallback);
            swipeDetector.UnregisterSwipeLeft(swipeLeftCallback);
            sessionManager.UnregisterSession(sessionCallback);
#endif
        
	} catch (std::exception& ex) {
		std::cout << ex.what() << std::endl;
	}
	
	if (rgbImage != NULL) {
		cvReleaseImage(&rgbImage);	
	}
	context.Shutdown();
	
	return 0;
}