利用KINECT+OPENCV檢測手勢的示範程式

來源:互聯網
上載者:User

2011-4-10 增加結果圖片,更新代碼,將模板改為6個(0-5)

 

1,原理:讀入KINECT深度資料,轉換為二值映像,找到輪廓,與輪廓模板比較,找到HU矩陣最小的為匹配結果

2,基礎:OPENNI, OPENCV2.2 以及http://blog.163.com/gz_ricky/blog/static/182049118201122311118325/
的常式基礎上修改

3,結果:僅僅用於示範利用OPENCV+OPENNI編程,對結果精度,處理速度等沒有最佳化,僅供參考

 

對0,1和5的比較比較準確

 

廢話少說,一切都在代碼中

// KinectOpenCVTest.cpp : 定義控制台應用程式的進入點。<br />//</p><p>#include "stdafx.h"</p><p>#include <stdlib.h><br />#include <iostream><br />#include <string><br />#include <XnCppWrapper.h><br />#include <opencv2/opencv.hpp></p><p>//#include "opencv/cv.h"<br />//#include "opencv/highgui.h"<br />using namespace std;<br />using namespace cv;</p><p>#define SAMPLE_XML_PATH "../../Data/SamplesConfig.xml"</p><p>//通用範本輪廓<br />vector<vector<Point>> g_TemplateContours;</p><p>//模板個數<br />int g_handTNum = 6;</p><p>void CheckOpenNIError( XnStatus eResult, string sStatus )<br />{<br />if( eResult != XN_STATUS_OK )<br />{<br />cerr << sStatus << " Error: " << xnGetStatusString( eResult ) << endl;<br />return;<br />}<br />}</p><p>//載入模板的輪廓<br />void init_hand_template()<br />{<br />//int handTNum = 10;<br />string temp = "HandTemplate/";</p><p>int i = 0;</p><p>for(i=0; i<g_handTNum; i++)<br />{<br />stringstream ss;<br />ss << i << ".bmp";</p><p>string fileName = temp + ss.str(); </p><p>//讀入灰階映像<br />Mat src = imread(fileName, 0);</p><p>if(!src.data)<br />{<br />printf("未找到檔案: %s/n", fileName);<br />continue;<br />}</p><p>vector<vector<Point>> contours;<br />vector<Vec4i> hierarchy;</p><p>findContours(src, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);<br />//findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);</p><p>g_TemplateContours.push_back(contours[0]);<br />}<br />}</p><p>//模板匹配手<br />int hand_template_match(Mat& hand)<br />{<br />//int handTNum = 10;<br />int minId = -1;<br />double minHu = 1;</p><p>double hu;<br />int method = CV_CONTOURS_MATCH_I1;</p><p>//match_num = 0;</p><p>for(int i=0; i<g_handTNum; i++){</p><p>Mat temp(g_TemplateContours.at(i));<br />hu = matchShapes(temp, hand, method, 0);</p><p>//找到hu矩最小的模板<br />if(hu < minHu){<br />minHu = hu;<br />minId = i;<br />}</p><p>//printf("%f ", hu);<br />}</p><p>//顯示匹配結果<br />int Hmatch_value = 25;//模板匹配係數</p><p>if(minHu<((double)Hmatch_value)/100)<br />return minId;<br />else<br />return -1;<br />}</p><p>void findHand(Mat& src, Mat& dst)<br />{<br />vector<vector<Point>> contours;<br />vector<Vec4i> hierarchy;</p><p>//找到外部輪廓<br />//findContours(src, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);<br />findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //CV_CHAIN_APPROX_NONE);<br />//findContours(src, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);</p><p>Mat dst_r = Mat::zeros(src.rows, src.cols, CV_8UC3);<br />dst_r.copyTo(dst);</p><p>// iterate through all the top-level contours,<br />// draw each connected component with its own random color<br />int idx = 0;<br />double maxArea = 0.0;<br />int maxId = -1;</p><p>for(unsigned int i = 0; i<contours.size(); i++)<br />{<br />Mat temp(contours.at(i));<br />double area = fabs(contourArea(temp));<br />if(area > maxArea)<br />{<br />maxId = i;<br />maxArea = area;<br />}<br />}</p><p>//for( ; idx >= 0; idx = hierarchy[idx][0] )<br />//{<br />////Scalar color( rand()&255, rand()&255, rand()&255 );<br />////drawContours(dst, contours, idx, color, CV_FILLED, 8, hierarchy );</p><p>//double area = contourArea(contours.at(idx));<br />//if(area > maxArea)<br />//{<br />//maxId = idx;<br />//maxArea = area;<br />//}<br />//}</p><p>//顯示最大輪廓外形,以及首選的模板ID<br />if(contours.size() > 0)<br />{<br />Scalar color(0, 255, 255 );<br />drawContours(dst, contours, maxId, color);</p><p>Mat hand(contours.at(maxId));<br />int value = hand_template_match(hand);</p><p>if(value >= 0)<br />{<br />Scalar templateColor(255, 0, 255 );<br />drawContours(dst, g_TemplateContours, value, templateColor);</p><p>printf("Match %d /r/n", value);</p><p>stringstream ss;<br />ss << "Match " << value;<br />string text = ss.str();<br />putText(dst, text, Point(300, 30), FONT_HERSHEY_SIMPLEX, 1.0, templateColor);<br />}<br />}<br />}</p><p>int HandDetect()<br />{<br />init_hand_template();</p><p>XnStatus eResult = XN_STATUS_OK; </p><p>// 1. initial val<br />xn::DepthMetaData m_DepthMD;<br />xn::ImageMetaData m_ImageMD;</p><p>// for opencv Mat<br />Mat m_depth16u( 480,640,CV_16UC1);<br />Mat m_rgb8u( 480,640,CV_8UC3);<br />Mat m_DepthShow( 480,640,CV_8UC1);<br />Mat m_ImageShow( 480,640,CV_8UC3);</p><p>Mat m_DepthThreshShow( 480,640,CV_8UC1);<br />Mat m_HandShow( 480,640,CV_8UC3);</p><p>//cvNamedWindow("depth");<br />//cvNamedWindow("image");<br />//cvNamedWindow("depthThresh");</p><p>char key=0;</p><p>// 2. initial context<br />xn::Context mContext; </p><p>eResult = mContext.Init(); </p><p>//xn::EnumerationErrors errors;<br />//eResult = mContext.InitFromXmlFile(SAMPLE_XML_PATH, &errors);</p><p>CheckOpenNIError( eResult, "initialize context" ); </p><p>//Set mirror<br />mContext.SetGlobalMirror(!mContext.GetGlobalMirror());</p><p>// 3. create depth generator<br />xn::DepthGenerator mDepthGenerator;<br />eResult = mDepthGenerator.Create( mContext );<br />CheckOpenNIError( eResult, "Create depth generator" ); </p><p>// 4. create image generator<br />xn::ImageGenerator mImageGenerator;<br />eResult = mImageGenerator.Create( mContext );<br />CheckOpenNIError( eResult, "Create image generator" );</p><p>// 5. set map mode<br />XnMapOutputMode mapMode;<br />mapMode.nXRes = 640;<br />mapMode.nYRes = 480;<br />mapMode.nFPS = 30;<br />eResult = mDepthGenerator.SetMapOutputMode( mapMode );<br />eResult = mImageGenerator.SetMapOutputMode( mapMode ); </p><p>//由於 Kinect 的深度攝像機和彩色攝像機是在不同的位置,而且鏡頭本身的參數也不完全相同,所以兩個攝像機所取得的畫面會有些微的差異<br />//將深度攝像機的視角調整到RGB攝像機位置<br />// 6. correct view port<br />mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerator ); </p><p>// 7. start generate data<br />eResult = mContext.StartGeneratingAll(); </p><p>// 8. read data<br />eResult = mContext.WaitNoneUpdateAll();<br />while( (key!=27) && !(eResult = mContext.WaitNoneUpdateAll( )) )<br />{<br />// 9a. get the depth map<br />mDepthGenerator.GetMetaData(m_DepthMD);<br />memcpy(m_depth16u.data,m_DepthMD.Data(), 640*480*2);</p><p>// 9b. get the image map<br />mImageGenerator.GetMetaData(m_ImageMD);<br />memcpy(m_rgb8u.data,m_ImageMD.Data(),640*480*3);</p><p>//將未知深度轉為白色,便於在OPENCV中分析<br />XnDepthPixel* pDepth = (XnDepthPixel*)m_depth16u.data;</p><p>for (XnUInt y = 0; y < m_DepthMD.YRes(); ++y)<br />{<br />for (XnUInt x = 0; x < m_DepthMD.XRes(); ++x, ++pDepth)<br />{<br />if (*pDepth == 0)<br />{<br />*pDepth = 0xFFFF;<br />}<br />}<br />}</p><p>//由於OpenNI獲得的深度圖片是16位不帶正負號的整數,而OpenCV顯示的是8位的,所以要作轉換。</p><p>//將距離轉換為灰階值(0-2550mm 轉換到 0-255),例如1000毫米轉換為 1000×255/2550 = 100<br />//m_depth16u.convertTo(m_DepthShow,CV_8U, 255/2096.0);<br />m_depth16u.convertTo(m_DepthShow,CV_8U, 255/2550.0);</p><p>//可以考慮根據資料縮減映像大小到有效範圍</p><p>//在此對灰階映像進行處理,平滑和去雜訊<br />//medianBlur(m_DepthShow, m_DepthThreshShow, 3);<br />//m_DepthThreshShow.copyTo(m_DepthShow);<br />//medianBlur(m_DepthThreshShow, m_DepthShow, 3);<br />blur(m_DepthShow, m_DepthThreshShow, Size(3, 3));<br />//m_DepthThreshShow.copyTo(m_DepthShow);<br />blur(m_DepthThreshShow, m_DepthShow, Size(3, 3));</p><p>Mat pyrTemp( 240,320,CV_8UC1);<br />pyrDown(m_DepthShow, pyrTemp);<br />pyrUp(pyrTemp, m_DepthShow);</p><p>//dilate(m_DepthShow, m_DepthThreshShow, Mat(), Point(-1,-1), 3);<br />//erode(m_DepthThreshShow, m_DepthShow, Mat(), Point(-1,-1), 3);</p><p>//for(int i = 0; i < m_depth16u.rows; i++)<br />//for(int j = 0; j < m_depth16u.cols; j++)<br />//{<br />//if(m_depth16u.at<unsigned short>(i,j) < 1)<br />//m_depth16u.at<unsigned short>(i,j) == 0xFFFF;</p><p>////m_depth16u.at<double>(i,j)=1./(i+j+1);<br />//}</p><p>//RGB和BGR在記憶體對應的位置序列不同,所以也要轉換。<br />cvtColor(m_rgb8u,m_ImageShow,CV_RGB2BGR);</p><p>//imshow("depth", m_DepthShow);<br />//imshow("image", m_ImageShow);</p><p>double thd_max = 0xFFFF;<br />double thd_val = 100.0;</p><p>//反轉黑白映像,以便找到最大外部輪廓<br />//threshold(m_DepthShow, m_DepthThreshShow, thd_val, thd_max, CV_THRESH_BINARY);<br />threshold(m_DepthShow, m_DepthThreshShow, thd_val, thd_max, CV_THRESH_BINARY_INV);<br />imshow("depthThresh", m_DepthThreshShow);</p><p>findHand(m_DepthThreshShow, m_HandShow);<br />imshow( "Hand", m_HandShow );</p><p>key=cvWaitKey(20);<br />}</p><p>// 10. stop<br />mContext.StopGeneratingAll();<br />mContext.Shutdown(); </p><p>return 0;<br />}</p><p>int _tmain(int argc, _TCHAR* argv[])<br />{<br />HandDetect();<br />}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.