ãããžã§ã¯ãã®ããŒããŠã§ã¢ã¯3ã€ã®éšåã§æ§æãããŠããŸãã
- 深床ã»ã³ãµãŒïŒãªãªãžãã«ã§ã¯ASUS XtionïŒ;
- å¶åŸ¡ã³ã³ãã¥ãŒã¿ãŒïŒCubieboard A80ãODROID-U3ïŒ;
- ãããžã§ã¯ã¿ãŒ
çæ³çã«ã¯ããã¹ãŠã®éçãåãããŠ700ãã«ä»¥äžãããããšã¯ãããŸããã AndroidãšLinuxã®äž¡æ¹ã§åäœããOpenNIãlibfreenectãªã©ã®ã€ã³ã¿ãŒãããäžã®ã©ã€ãã©ãªãããããã3ã€ã®éšåãã¹ãŠãæ¥ç¶ããã®ã¯æ¯èŒçç°¡åã§ãããšæ³å®ãããŠããŸããã åæ段éã§ã¯çµéšãäžè¶³ããŠãããããããŒããŠã§ã¢ãšOSã®äž¡æ¹ã«éžæè¢ãããããã«æãããŸããã ãªãŒãã³ãœãŒã¹ã®äŸãããããã¹ãŠããŸãšããããšã¯å€§ããããšã§ã¯ãããŸããã ãããžã§ã¯ãã®éå§åŸãã°ããããŠãããã¯ããã§ã¯ãªãããšãå€æããŸããã ãã¹ãŠã®éšåãçµ±åããã¿ãŒã²ããããã€ã¹ã§ã©ã€ãã©ãªãå®è¡ããããšãããæãé£ããã¿ã¹ã¯ã§ãã Linuxã®æ§æã«é¢ããæ å ±ã®å ¥æå¯èœæ§ãšãAndroidãã©ãããã©ãŒã ã®åžå Žã«ããè±å¯ãªã¢ããªã±ãŒã·ã§ã³ã®éã§éžæããå¿ èŠããããŸããã
ãã ããæåã«ãŸãæåã«ã
ããŒããŠã§ã¢ã®å®éšãããã«éå§ããããã«ã䜿çšæžã¿ã®Microsoft Kinectã»ã³ãµãŒãšãããžã§ã¯ã¿ãŒãè³Œå ¥ããŸããã 次ã«ããããžã§ã¯ã¿ãŒãšã»ã³ãµãŒã®ããŠã³ãã¯æ£æ¹åœ¢ã®ãã€ãã§äœãããŠããŸãïŒ
倩äºã«åãä»ããããã«ãã³ãŒããŒã®å°ããªéšåãããŠã³ãã®äžéšã«æº¶æ¥ãããŠããŸãã ãã€ããæ²ããå Žæã§ã¯ãæ§é ã匷åããããã«ã¹ã«ãŒãã®åœ¢ã®ãã¬ãŒãã溶æ¥ãããŸãã ãããžã§ã¯ã¿ã¯ãäžè§åœ¢ã®åæ¿ãã¬ãŒããä»ããŠããŠã³ãã«æ¥ç¶ãããŠããŸãã ã»ã³ãµãŒãããŠã³ãã«æ¥ç¶ããã«ã¯ãebayã§ç°¡åã«èŠã€ããããšãã§ããKinectçšã®ç¹å¥ãªã¢ã¯ã»ãµãªãŒã䜿çšããŸãã ã³ã¹ããåæžããããã«ãå¶åŸ¡ã³ã³ãã¥ãŒã¿ãŒãšããŠåé¡ãªãebayã§ãèŠã€ããããšãã§ããCubieboard A10ããŒããéžã°ããŸããã å·çã®æç¹ã§ãCubieboard A20ãšA80ã2ã³ã¢ãš8ã³ã¢ã®ã«ãŠã³ã¿ãŒããŒãã¯ãã§ã«ãªãªãŒã¹ãããŠããŸãã äºç®ãèš±ãã°ãA80ãè³Œå ¥ããŠãã·ã¹ãã ããŠãŒã¶ãŒã¢ããªã±ãŒã·ã§ã³ãšæ·±åºŠã»ã³ãµãŒããã®ããŒã¿ããã£ããã£ããã³åŠçããããã®ãµãŒãã¹ãåæã«æäœããããã®ãã¯ãŒãªã¶ãŒããæã€ããã«ããããšããå§ãããŸãã ããŒããšã»ã³ãµãŒã¯ã4Aã®åºåé»æµãæã€USBé»æºãã絊é»ãããŸãã 深床ã«ã¡ã©ããããžã§ã¯ã¿ãŒã¬ã³ãºãšåãå¹³é¢ã«ããããã«ããããžã§ã¯ã¿ãŒãšã»ã³ãµãŒã¯ããŠã³ãã«æ¥ç¶ãããŸãã
è¿è·é¢ããå¯èœãªéãç»åã倧ãããªããããªãããžã§ã¯ã¿ãŒã¢ãã«ãéžæããããšããå§ãããŸãã ééšåã®ãã®èª¬æã¯å®äºã§ããŸãã 次ã«ãœãããŠã§ã¢ã«ã€ããŠã
ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãšããŠãCubieboardã§ã®Androidã®ã¢ã»ã³ããªãéžæããããã¹ã¯ãããã«é¢çœãã¹ã¯ãªãŒã³ã»ãŒããŒã衚瀺ãããŸããã Androidã§ã¯ã¢ãžã¥ãŒã«ã®ããŒãã®é åºãå€æŽã§ããªããããæ§æãã¡ã€ã«ãå°ã調æŽããã¢ã»ã³ããªãèªåã§ã³ã³ãã€ã«ããå¿ èŠããããŸãããããããã·ã¹ãã ã®æ¬¡ã®åèµ·åãŸã§ã§ãã
ã€ãã³ããå®è£ ããã«ã¯ãsun4i-tsã¿ããã¹ã¯ãªãŒã³ãã©ã€ããŒã¢ãžã¥ãŒã«ãå¿ èŠã§ããã å®éããã¹ãã¢ããªã±ãŒã·ã§ã³ã¯TUIOã¯ã©ã€ã¢ã³ããå®è£ ããŠããŸãããå€æããããã«ãã¿ããããã«ãã©ã€ããŒã䜿çšããŠããAndroidçšã«ååšããTUIOãµãŒããŒã¯ãã«ãã¿ããã€ãã³ãããµããŒãããŸããã ããã¯ãããããAllwinnerã®äžã®sun4i-tsã¿ããããããã©ã€ããŒèªäœã«ãããã®ã§ãã ãããã®äºå®ã«åºã¥ããŠãã€ãã³ããçŽæ¥å®è£ ããããªã¢ã³ããéžæãããŸããã
深床ããŒã¿ããã£ããã£ããã«ã¯ã軜éã§é«éãªlibfreenectã©ã€ãã©ãªã䜿çšããŸãããã®ã©ã€ãã©ãªã¯ãlibusbã䜿çšããŠUSBçµç±ã§ããŒã¿ã転éããŸãã ååŸãã深床ããŒã¿ã¯ãOpenCV for Androidã䜿çšããŠåŠçãããŸãã åŠçã®æ¬è³ªã¯éåžžã«åçŽã§ããããã¹ãããããããå€ä»¥äžã®é·ãã®éã«ãŒãã«å€æããŠãåœéœæ§ãæé€ãããããã®å¹ŸäœåŠçäžå¿ãèŠã€ããå¿ èŠããããŸãã
äœæ¥ã®æåã®æ®µéã§ãã·ãŒã³ã«ãªããžã§ã¯ãããªãå Žåãã¢ããªã±ãŒã·ã§ã³ã¯èæ¯æ·±åºŠããããäœæãããã®ããã»ã¹ã§ãããã䜿çšããŠèæ¯ããã¿ãŒã²ãããªããžã§ã¯ããåé¢ããŸãã ã¢ããªã±ãŒã·ã§ã³ã¯ãå¶åŸ¡éšåã§ãããC / C ++ã³ãŒããæã€ãµãŒãã¹ã§ãã 深床ããŒã¿ãåŠçããã³ãã£ããã£ããããã®ãã¹ãŠã®ããžãã¯ã¯ãC / C ++ã§å®è£ ãããŠããŸãã TUIOãšOpenCVãæäœããããã®ã³ãŒãã®äžéšã¯ãgithubã®ãã®ãããžã§ã¯ãããåãããŸããã
ã³ãŒãããã詳现ã«æ€èšããŠãã ããã ç§ãèšã£ãããã«ãã³ãŒãã¯OpenCVã䜿çšããŠããŸãã æåã«ãã¢ããªã±ãŒã·ã§ã³ã¯æ·±åºŠããããäœæããŸãã
1 void STouchDetector::process(const uint16_t& depthData) { 2 frmCount++; 3 // create background model (average depth) 4 if (frmCount < BackgroundTrain) { 5 depth.data = (uchar*)(&depthData); 6 buffer[frmCount] = depth; 7 } 8 else { 9 if (frmCount == BackgroundTrain) { 10 // Calculate average depth based on all frames from buffer 11 average(buffer, background); 12 Scalar bmeanVal = mean(background(roi)); 13 double bminVal = 0.0, bmaxVal = 0.0; 14 minMaxLoc(background(roi), &bminVal, &bmaxVal); 15 LOGD("Background extraction completed. Average depth is %f min %f max %f", bmeanVal.val[0], bminVal, bmaxVal); 16 }
6è¡ç®ã§ã¯ã深床ããŒã¿ããããã¡ã«ä¿åãããŸãã ãããã¡ã®ã¿ã€ãã¯std :: vector <cv :: Mat1s>ã§ããããšã«æ³šæããŠãã ããã ããã¯è¡åã®é åã§ããã6è¡ç®ã®å²ãåœãŠã¯å®éã«ã¯ãã¬ãŒã ã®ãã¹ãŠã®ãã¯ã»ã«ããããã¡ãŒã«ã³ããŒããŠããŸãã ãã¬ãŒã ã«ãŠã³ã¿ãŒããããå€BackgroundTrainã«éãããšã11è¡ç®ã®ãã¹ãŠã®ãã¬ãŒã ã®å¹³å深床å€ãèšç®ããé¢æ°ãåŒã³åºãããŸãã
1 void STouchDetector::average(vector<Mat1s>& frames, Mat1s& mean) { 2 Mat1d acc(mean.size()); 3 Mat1d frame(mean.size()); 4 for (unsigned int i=0; i<frames.size(); i++) { 5 frames[i].convertTo(frame, CV_64FC1); 6 acc = acc + frame; 7 } 8 acc = acc / frames.size(); 9 acc.convertTo(mean, CV_16SC1); 10 }
äžèšã®é¢æ°ã§ã¯ã2ãã€ãæŽæ°ã®ãããªãã¯ã¹ãæµ®åå°æ°ç¹æ°ã®ãããªãã¯ã¹ã«å€æããã次ã«ããããªãŒããããªãã¯ã¹ã«è¿œå ãããæçµçã«å¹³åãèšç®ãããŸãã 8è¡ç®ã§ã¯ãè¡åã®åèŠçŽ ã«å¯ŸããŠé€ç®ãå®è¡ãããŸãã
ã³ãŒãã®æ¬¡ã®éšåã§ã¯ã4è¡ç®ã®åã«äœæãã深床èæ¯ã䜿çšããŠãªããžã§ã¯ããéžæããŸãã次ã«ãOpenCV findContoursïŒïŒé¢æ°ã䜿çšããŠã茪éãéžæããŸãã ãããå€ãããé·ãé·ãã®èŒªéã®å Žåã幟äœåŠçäžå¿ãèšç®ãããŸãã åãåã£ãäžå¿ã®åº§æšã¯touchPointsé åã«è¿œå ãããè¡šé¢ãã¯ãªãã¯ããã€ãã³ãã®åº§æšãä¿åããŸãïŒ
1 // Update 16 bit depth matrix 2 depth.data = (uchar*)(&depthData); 3 // Extract foreground by simple subtraction of very basic background model 4 foreground = background - depth; 5 6 // Find touch mask by thresholding (points that are close to background = touch points) 7 touch = (foreground > TouchDepthMin) & (foreground < TouchDepthMax); 8 9 // Extract ROI 10 Mat touchRoi = touch(roi); 11 12 // Find contours by depth data 13 vector< vector<Point2i> > contours; 14 vector<Point2f> touchPoints; 15 findContours(touchRoi, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point2i(xMin, yMin)); 16 17 for (unsigned int i=0; i < contours.size(); i++) { 18 Mat contourMat(contours[i]); 19 // Find touch points by area thresholding 20 if ( contourArea(contourMat) > ContourAreaThreshold ) { 21 Scalar center = mean(contourMat); 22 Point2i touchPoint(center[0], center[1]); 23 touchPoints.push_back(touchPoint); 24 } 25 }
æåŸã®éšåã§ã¯ãã€ãã³ããã·ã¹ãã ã«éä¿¡ãããŸãã è¡šé¢ã¿ããã€ãã³ãã®åº§æšã¯ã以åã«äœæãããtouchPointsé åããååŸãããŸãã
1 // Send TUIO cursors 2 tuioTime = TuioTime::getSessionTime(); 3 tuio->initFrame(tuioTime); 4 5 for (unsigned int i=0; i < touchPoints.size(); i++) { // touch points 6 float cursorX = (touchPoints[i].x - xMin) / (xMax - xMin); 7 float cursorY = 1 - (touchPoints[i].y - yMin) / (yMax - yMin); 8 TuioCursor* cursor = tuio->getClosestTuioCursor(cursorX,cursorY); 9 10 LOGD("Touch detected %d %d", (int)touchPoints[i].x, (int)touchPoints[i].y); 11 12 // TODO improve tracking (don't move cursors away, that might be closer to another touch point) 13 if (cursor == nullptr || cursor->getTuioTime() == tuioTime) { 14 tuio->addTuioCursor(cursorX,cursorY); 15 eventInjector->sendEventToTouchDevice((int)(touchPoints[i].x - xMin), 16 (int)(touchPoints[i].y - yMin)); 17 LOGD("TUIO cursor was added at %d %d", (int)touchPoints[i].x, (int)touchPoints[i].y); 18 } else { 19 tuio->updateTuioCursor(cursor, cursorX, cursorY); 20 } 21 }
ã€ãã³ããã·ã¹ãã ã«éä¿¡ããã«ã¯ãsendEventToTouchDriverïŒïŒé¢æ°ãåŒã³åºãããTUIOã¡ãã»ãŒãžããµãŒããŒã«éä¿¡ããã«ã¯ãaddTuioCursorïŒïŒããã³updateTuioCursorïŒïŒé¢æ°ãåŒã³åºãããŸãã
ã³ãŒãã®èª¬æã®æåŸã«ãã·ã¹ãã ã«ã€ãã³ããéä¿¡ããããã®ã¢ãžã¥ãŒã«ã«ã€ããŠã話ããããšæããŸãã ã¢ãžã¥ãŒã«ã¯stouchEventInjector.cppãšåŒã°ããŸãã ã³ã³ã¹ãã©ã¯ã¿ãŒã§ã®äœæ¥ã®æåã«ãopenïŒïŒé¢æ°ã䜿çšããŠãå ¥åããã€ã¹/ dev / input / eventXã®ã€ãã³ããã¡ã€ã«ãéããŸãïŒXã¯æ°å€ïŒã ã¢ãžã¥ãŒã«èªäœã¯ãç®çã®ãã©ã€ããŒïŒsun4i_tsïŒã«é¢é£ä»ãããããã³ãã«ãèŠã€ããããšããŸãã ãããè¡ãã«ã¯ãæ¢åã®åãã¡ã€ã«/ dev / input / eventXã«å¯ŸããŠ-plã¹ã€ããã䜿çšããŠgeteventé¢æ°ãé çªã«åŒã³åºããŸãã ã€ãã³ãã®éä¿¡ã¯ãå®éã«ã¯ãwriteïŒïŒé¢æ°ã䜿çšããŠãuinput_eventæ§é äœã®/ dev / input / eventXãã¡ã€ã«ã«æžã蟌ãã§ããŸãã ã¿ããã¹ã¯ãªãŒã³ã«ã¯ã軞äžã®æ倧å€ãšæå°å€ãæã€ç¬èªã®åº§æšç³»ããããŸããsun4i-tsã®å Žåãäž¡æ¹ã®è»žã®æ倧æ°ã¯ohãšoh 4095ã§ãã ïŒ
åé ã§è¿°ã¹ãããã«ãããã€ã¹ã®èµ·ååŸã«ã¿ããã¹ã¯ãªãŒã³ãã©ã€ããŒãèªåçã«èµ·åããã«ã¯ãAndroidã¢ã»ã³ããªã®æ§æãå€æŽããå¿ èŠããããŸãã ç§ã®å ŽåãUbuntuã®ææ°ããŒãžã§ã³ã§ããAndroidããã«ãããã«ã¯ãããŒãžã§ã³ã¯14.10ã§ããã ãããããœãŒã¹ã³ãŒããCubieboard A10 AndroidããåãåºããŠå±éããŸãã 2ã€ã®ãã¡ã€ã«ãå€æŽããå¿ èŠããããŸãã
android/device/softwinner/apollo-cubieboard/init.sun4i.rc android/frameworks/base/data/etc/platform.xml
init.sun4i.rcãã¡ã€ã«ã§ãinsmod /system/vendor/modules/sun4i-ts.koã®è¡ã®ã³ã¡ã³ãã解é€ããå¿ èŠããããŸãã platform.xmlãã¡ã€ã«ã§ãUSBãå ¥åãããã³ã·ã§ã«ã°ã«ãŒããINTERNETã»ã¯ã·ã§ã³ã«è¿œå ããå¿ èŠããããŸãã
<group gid="usb"/> <group gid="input"/> <group gid="shell"/>
å€æŽãè¡ã£ãåŸã次ã®ã³ãã³ãã§ã¢ã»ã³ããªãéå§ããŸãã
./build.sh -p sun4i_crane -k 3.0
Android ICSããŒãžã§ã³ããã«ãããã«ã¯ãGCCã³ã³ãã€ã©ããŒãžã§ã³4.6ãšããŒãžã§ã³3.81ãå¿ èŠã§ãã ã³ã³ãã€ã©ãŒãšmakeããŒãžã§ã³ãå¿ èŠãªãã®ãšç°ãªãå Žåã¯ã次ã®ã³ãã³ãã§å€æŽã§ããŸãã
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9 sudo update-alternatives --config gcc sudo mv /usr/bin/make /usr/bin/make40 sudo update-alternatives --install /usr/bin/make make /usr/local/bin/make 60 sudo update-alternatives --install /usr/bin/make make /usr/bin/make40 40 sudo update-alternatives --config make
次ã«ã Cubieboard A10 AndroidããŒãžã®æ瀺ã«åŸããŸãã ãã«ãããã»ã¹äžã«ã³ã³ãã€ã«ãšã©ãŒãçºçããå ŽåããããŸãã ãšã©ãŒãä¿®æ£ããããã®ãã³ãã¯ããœãŒã¹ãªããžããªã®fix_android_firmware.readmeãã¡ã€ã«ã®Fix building issuesã»ã¯ã·ã§ã³ã«ãããŸãã ããŒããPCã«æ¥ç¶ããã«ã¯ãããã€ã¹ãUSBçµç±ã§æ¥ç¶ããããã®ã«ãŒã«ãè¿œå ããå¿ èŠããããŸãããããè¡ãã«ã¯ããã¡ã€ã«ãäœæããŸãã
/etc/udev/rules.d/51-android.rules
ãããŠã次ã®è¡ãè¿œå ããŸãã
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="0003",MODE="0666"
å€æŽãæå¹ã«ããã«ã¯ãudevãµãŒãã¹ãåèµ·åããŸãã
$sudo chmod a+rx /etc/udev/rules.d/51-android.rules $sudo service udev restart
ããŒããPCã«æ¥ç¶ãã LiveSuitãŠãŒãã£ãªãã£ã䜿çšããŠãã¡ãŒã ãŠã§ã¢ã€ã¡ãŒãžsun4i_crane_cubieboard.imgãå ¥åããŸãã ã€ã³ã¹ããŒã«ããåã«ãLiveSuitã®æ瀺ã泚ææ·±ãèªãã§ãã ãããæ£ããã€ã³ã¹ããŒã«ãããŠããªããšãã¢ããªã±ãŒã·ã§ã³ã¯ããã€ã¹ã«ã€ã¡ãŒãžãããŠã³ããŒãã§ããŸããã ã€ã¡ãŒãžãããŒãããŠããŒããåèµ·åããããSimpleTouchã¢ããªã±ãŒã·ã§ã³ãã€ã³ã¹ããŒã«ããŠå®è¡ã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ã¯ãKinectããããŒã¿ããã£ããã£/åŠçããã€ãã³ããã·ã¹ãã ã«éä¿¡ãããµãŒãã¹ãèªåçã«éå§ããŸãã ã¢ããªã±ãŒã·ã§ã³ãåçŽã«æå°åããŠãPlayMarketããã²ãŒã ãå®è¡ã§ããŸãã
ãœãŒã¹ã³ãŒãã¯bitbucketããããŠã³ããŒãã§ããŸãã
ãã¢ã³ã¹ãã¬ãŒã·ã§ã³ãããªïŒ