C++基于OpenCV實現(xiàn)手勢識別的源碼
先給大家上效果圖:

源碼在下面
使用 RGB 值分割手部區(qū)域,即手部的 GB 值將與背景不同
或者使用邊緣檢測
或者
背景減法。
我這里使用了背景減法模型。OpenCV為我們提供了不同的背景減法模型,codebook 它的作用是對某些幀進(jìn)行一段時間的精確校準(zhǔn)。其中對于它獲取的所有圖像;它計算每個像素的平均值和偏差,并相應(yīng)地指定框。
在前景中它就像一個黑白圖像,只有手是白色的

用 Convex Hull 來找到指尖。Convex hull 基本上是包圍手部區(qū)域的凸集。

包圍手的紅線是凸包?;旧纤且粋€凸起;如果我們在紅色區(qū)域內(nèi)取任意兩點并將它們連接起來形成一條線,那么這條線就完全位于集合內(nèi)。

黃點是缺陷點,會有很多這樣的缺陷點,即每個谷都有一個缺陷點?,F(xiàn)在根據(jù)缺陷點的數(shù)量,我們可以計算展開的手指數(shù)量。
大概就是
手部區(qū)域提取是使用背景減法完成的。
對于尖端點,深度點凸度缺陷。
提取輪廓和檢測凸點的主要代碼在函數(shù)中
無效檢測(IplImage* img_8uc1,IplImage* img_8uc3);
將相機放在穩(wěn)定的背景前;運行代碼,等待一段時間。校準(zhǔn)完成后。你會看到顯示一些干擾的連接組件圖像。把你的手放在相機視圖中。
沒什么好說的直接看代碼會比較容易理解
核心代碼
int main(int argc, char** argv)
{
const char* filename = 0;
IplImage* rawImage = 0, *yuvImage = 0;
IplImage *ImaskCodeBook = 0,*ImaskCodeBookCC = 0;
CvCapture* capture = 0;
int c, n, nframes = 0;
int nframesToLearnBG = 300;
model = cvCreateBGCodeBookModel();
model->modMin[0] = 3;
model->modMin[1] = model->modMin[2] = 3;
model->modMax[0] = 10;
model->modMax[1] = model->modMax[2] = 10;
model->cbBounds[0] = model->cbBounds[1] = model->cbBounds[2] = 10;
bool pause = false;
bool singlestep = false;
for( n = 1; n < argc; n++ )
{
static const char* nframesOpt = "--nframes=";
if( strncmp(argv[n], nframesOpt, strlen(nframesOpt))==0 )
{
if( sscanf(argv[n] + strlen(nframesOpt), "%d", &nframesToLearnBG) == 0 )
{
help();
return -1;
}
}
else
filename = argv[n];
}
if( !filename )
{
printf("Capture from camera\n");
capture = cvCaptureFromCAM( 0 );
}
else
{
printf("Capture from file %s\n",filename);
capture = cvCreateFileCapture( filename );
}
if( !capture )
{
printf( "Can not initialize video capturing\n\n" );
help();
return -1;
}
for(;;)
{
if( !pause )
{
rawImage = cvQueryFrame( capture );
++nframes;
if(!rawImage)
break;
}
if( singlestep )
pause = true;
if( nframes == 1 && rawImage )
{
// CODEBOOK METHOD ALLOCATION
yuvImage = cvCloneImage(rawImage);
ImaskCodeBook = cvCreateImage( cvGetSize(rawImage), IPL_DEPTH_8U, 1 );
ImaskCodeBookCC = cvCreateImage( cvGetSize(rawImage), IPL_DEPTH_8U, 1 );
cvSet(ImaskCodeBook,cvScalar(255));
cvNamedWindow( "Raw", 1 );
cvNamedWindow( "ForegroundCodeBook",1);
cvNamedWindow( "CodeBook_ConnectComp",1);
}
if( rawImage )
{
cvCvtColor( rawImage, yuvImage, CV_BGR2YCrCb );
if( !pause && nframes-1 < nframesToLearnBG )
cvBGCodeBookUpdate( model, yuvImage );
if( nframes-1 == nframesToLearnBG )
cvBGCodeBookClearStale( model, model->t/2 );
if( nframes-1 >= nframesToLearnBG )
{
cvBGCodeBookDiff( model, yuvImage, ImaskCodeBook );
centers if desired
cvCopy(ImaskCodeBook,ImaskCodeBookCC);
cvSegmentFGMask( ImaskCodeBookCC );
cvShowImage( "CodeBook_ConnectComp",ImaskCodeBookCC);
detect(ImaskCodeBookCC,rawImage);
}
cvShowImage( "Raw", rawImage );
cvShowImage( "ForegroundCodeBook",ImaskCodeBook);
}
c = cvWaitKey(10)&0xFF;
c = tolower(c);
if(c == 27 || c == 'q')
break;
switch( c )
{
case 'h':
help();
break;
case 'p':
pause = !pause;
break;
case 's':
singlestep = !singlestep;
pause = false;
break;
case 'r':
pause = false;
singlestep = false;
break;
case ' ':
cvBGCodeBookClearStale( model, 0 );
nframes = 0;
break;
case 'y': case '0':
case 'u': case '1':
case 'v': case '2':
case 'a': case '3':
case 'b':
ch[0] = c == 'y' || c == '0' || c == 'a' || c == '3';
ch[1] = c == 'u' || c == '1' || c == 'a' || c == '3' || c == 'b';
ch[2] = c == 'v' || c == '2' || c == 'a' || c == '3' || c == 'b';
printf("CodeBook YUV Channels active: %d, %d, %d\n", ch[0], ch[1], ch[2] );
break;
case 'i':
case 'o':
case 'k':
case 'l':
{
uchar* ptr = c == 'i' || c == 'o' ? model->modMax : model->modMin;
for(n=0; n<NCHANNELS; n++)
{
if( ch[n] )
{
int v = ptr[n] + (c == 'i' || c == 'l' ? 1 : -1);
ptr[n] = CV_CAST_8U(v);
}
printf("%d,", ptr[n]);
}
printf(" CodeBook %s Side\n", c == 'i' || c == 'o' ? "High" : "Low" );
}
break;
}
}
cvReleaseCapture( &capture );
cvDestroyWindow( "Raw" );
cvDestroyWindow( "ForegroundCodeBook");
cvDestroyWindow( "CodeBook_ConnectComp");
return 0;
}
要直接跑代碼調(diào)試的,可以直接去下載
到此這篇關(guān)于C++基于OpenCV實現(xiàn)手勢識別的源碼的文章就介紹到這了,更多相關(guān)OpenCV手勢識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中你不知道的隱式類型轉(zhuǎn)換規(guī)則詳解
在C語言中,類型轉(zhuǎn)換的方式一般可分為隱式類型轉(zhuǎn)換和顯示類型轉(zhuǎn)換(也稱為強制類型轉(zhuǎn)換),其中隱式類型轉(zhuǎn)換由編譯器自動進(jìn)行,不需要程序員干預(yù),本文給大家詳細(xì)介紹了C語言中隱式類型轉(zhuǎn)換規(guī)則,需要的朋友可以參考下2024-01-01
C++類與對象深入之靜態(tài)成員與友元及內(nèi)部類詳解
朋友們好,這篇播客我們繼續(xù)C++的初階學(xué)習(xí),現(xiàn)在對我們對C++的靜態(tài)成員,友元,內(nèi)部類知識點做出總結(jié),整理出來一篇博客供我們一起復(fù)習(xí)和學(xué)習(xí),如果文章中有理解不當(dāng)?shù)牡胤?還希望朋友們在評論區(qū)指出,我們相互學(xué)習(xí),共同進(jìn)步2022-06-06
C語言之實現(xiàn)棧的基礎(chǔ)創(chuàng)建
這篇文章主要介紹了C語言之實現(xiàn)棧的基礎(chǔ)創(chuàng)建,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++?重載運算符在HotSpot?VM中的應(yīng)用小結(jié)
C++支持運算符重載,對于Java開發(fā)者來說,這個可能比較陌生一些,因為Java不支持運算符重載,下面介紹一下HotSpot?VM中的運算符重載,感興趣的朋友跟隨小編一起看看吧2023-09-09
最短時間學(xué)會基于C++實現(xiàn)DFS深度優(yōu)先搜索
常見使用深度優(yōu)先搜索(DFS)以及廣度優(yōu)先搜索(BFS)這兩種搜索,今天我們就來講講什么是深度優(yōu)先搜索,感興趣的可以了解一下2021-08-08

