日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kinect学习(三):获取RGB颜色数据

發(fā)布時(shí)間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kinect学习(三):获取RGB颜色数据 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

在前面的文章中介紹了如何搭建Kinect開發(fā)環(huán)境:Kinect學(xué)習(xí)(一):開發(fā)環(huán)境搭建。搭建好環(huán)境后,首先要做的當(dāng)然就是試著讀取Kinect中的數(shù)據(jù)了。

Kinect有三個(gè)鏡頭,中間的是RGB攝像頭,左邊的是紅外線發(fā)射器,右邊的是紅外線CMOS攝像頭構(gòu)成的3D結(jié)構(gòu)光攝像頭,用來采集深度數(shù)據(jù)。彩色攝像頭最大支持1280*960分辨率成像,紅外攝像頭最大支持640*480成像。

接下來就要通過微軟提供的SDK來讀取Kinect中的彩色攝像頭的數(shù)據(jù)了。

代碼

先上代碼,里面有注釋,后面再詳細(xì)介紹。

#include <windows.h> #include <NuiApi.h> #include <iostream> #include <opencv2/opencv.hpp>/* 幾個(gè)常用的頭文件: 1、NuiApi.h ---包含所有的NUI(自然用戶界面) API頭文件和定義基本的初始化和函數(shù)訪問入口。這是我們C++工程的主要頭文件,它已經(jīng)包含了NuiImageCamera.h 和 NuiSkeleton.h。 2、NuiImageCamera.h ---定義了圖像和攝像頭服務(wù)的API,包括調(diào)整攝像頭的角度和仰角,打開數(shù)據(jù)流和讀取數(shù)據(jù)流等。 3、NuiSkeleton.h ---骨架有關(guān)的API,包括使能骨架跟蹤,獲取骨架數(shù)據(jù),骨架數(shù)據(jù)轉(zhuǎn)換和平滑渲染等。 4、NuiSensor.h ---音頻API,包括ISoundSourceLocalizer接口,用于返回聲源的方向(波束形成)和音頻的位置。 */using namespace std; using namespace cv;int main(int argc, char* argv[]) {cv::Mat img;img.create(480, 640, CV_8UC3);//1、初始化NUIHRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);if (FAILED(hr)){cout << "NuiInitialize failed" << endl;return hr;}//2、定義事件句柄//創(chuàng)建讀取下一幀的信號(hào)事件句柄,控制KINECT是否可以開始讀取下一幀數(shù)據(jù)HANDLE nextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);HANDLE colorStreamHandle = NULL;//保存圖像數(shù)據(jù)流的句柄,用于提取數(shù)據(jù)//3、打開KINECT設(shè)備的彩色信息通道,并用colorStreamHandle保存該流的句柄,以便于以后讀取hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, 0, 2, nextColorFrameEvent, &colorStreamHandle);if (FAILED(hr)){cout << "Could not open color image stream video" << endl;NuiShutdown();return hr;}cv::namedWindow("colorImage", CV_WINDOW_AUTOSIZE);//4、開始讀取彩色圖數(shù)據(jù)while (1){const NUI_IMAGE_FRAME * pImageFrame = NULL;//4.1、無線等待新的數(shù)據(jù),等到就返回if (WaitForSingleObject(nextColorFrameEvent, INFINITE) == 0){//4.2、從剛才打開數(shù)據(jù)流的流句柄中得到該幀的數(shù)據(jù),讀取到的數(shù)據(jù)地址存于pImageFrame中hr = NuiImageStreamGetNextFrame(colorStreamHandle, 0, &pImageFrame);if (FAILED(hr)){cout << "Could not get color image" << endl;NuiShutdown();return -1;}INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;NUI_LOCKED_RECT LockedRect;//4.3、提取數(shù)據(jù)幀到LockedRect(它包括兩個(gè)數(shù)據(jù)對(duì)象:pitch每行字節(jié)數(shù),pBits第一個(gè)字節(jié)地址)//并鎖定數(shù)據(jù),這樣當(dāng)我們讀取數(shù)據(jù)的時(shí)候,kinect就不會(huì)去修改它pTexture->LockRect(0, &LockedRect, NULL, 0);//4.4、確認(rèn)獲得的數(shù)據(jù)是否有效if (LockedRect.Pitch != 0){//4.5、將數(shù)據(jù)轉(zhuǎn)換為OpenCV的Mat格式for (int i = 0; i < img.rows; i++){uchar *ptr = img.ptr<uchar>(i); //第i行的指針//每個(gè)字節(jié)代表一個(gè)顏色信息,直接使用ucharuchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;for (int j = 0;j < img.cols;j++){//內(nèi)部數(shù)據(jù)是4個(gè)字節(jié),0-1-2是BGR,第4個(gè)現(xiàn)在未使用ptr[3 * j] = pBuffer[4 * j];ptr[3 * j + 1] = pBuffer[4 * j + 1];ptr[3 * j + 2] = pBuffer[4 * j + 2];}}cv::imshow("colorImage", img); //顯示圖像}else{cout << "Buffer length of received texture is bogus\r\n" << endl;}//5、這幀已經(jīng)處理完了,所以將其解鎖pTexture->UnlockRect(0);//6、釋放本幀數(shù)據(jù),準(zhǔn)備獲取下一幀NuiImageStreamReleaseFrame(colorStreamHandle, pImageFrame);}if (cv::waitKey(20) == 27)break;}//7、關(guān)閉NUI連接NuiShutdown();return 0; }

運(yùn)行結(jié)果

說明

整個(gè)程序可以分為以下流程:

  • 初始化NUI接口;
  • 定義事件句柄;
  • 打開Kinect設(shè)備的數(shù)據(jù)流(彩色RGB);
  • 等待數(shù)據(jù)更新,若更新完成則進(jìn)行下一步;
  • 從數(shù)據(jù)流中拿出圖像數(shù)據(jù);
  • 提取數(shù)據(jù)幀并鎖定數(shù)據(jù);
  • 將數(shù)據(jù)轉(zhuǎn)換為OpenCV的Mat格式。
  • 1、初始化NUI接口

    //1、初始化NUI HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);

    要使用微軟提供的SDK中的SDK來操作Kinect,必須先調(diào)用NUI初始化函數(shù)。
    函數(shù)原型為:

    HRESULT NuiInitialize(DWORD dwFlags);

    dwFlags表示標(biāo)志位,有以下幾種情況:

    • NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX: 提供帶用戶信息的深度圖數(shù)據(jù);
    • NUI_INITIALIZE_FLAG_USES_COLOR:提供RGB彩色圖像數(shù)據(jù);
    • NUI_INITIALIZE_FLAG_USES_SKELETON:提供骨骼點(diǎn)數(shù)據(jù);
    • NUI_INITIALIZE_FLAG_USES_DEPTH:提供深度圖像數(shù)據(jù);
    • NUI_INITIALIZE_FLAG_USES_AUDIO:提供聲音數(shù)據(jù);
    • NUI_INITIALIZE_DEFAULT_HARDWARE_THREAD:初始化默認(rèn)的硬件線程;

    以上的都各自對(duì)應(yīng)一個(gè)標(biāo)志位,使用時(shí)可以使用|將它們組合起來。

    注意到,它還返回了一個(gè)HRESULT類型的參數(shù),通過它可以判斷初始化函數(shù)是否執(zhí)行成功。

    if (FAILED(hr)) {cout << "NuiInitialize failed" << endl;return hr; }

    或者判斷是否等于S_OK:

    if(hr == S_OK) {cout << "NuiInitialize successfully" << endl; }

    2、定義事件句柄

    //2、定義事件句柄 //創(chuàng)建讀取下一幀的信號(hào)事件句柄,控制KINECT是否可以開始讀取下一幀數(shù)據(jù) HANDLE nextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    該函數(shù)會(huì)創(chuàng)建一個(gè)windows事件對(duì)象,創(chuàng)建成功則返回事件的句柄。這里的這個(gè)事件是用來判斷是否有新數(shù)據(jù)的。
    其中有四個(gè)參數(shù):

    • 第一個(gè)是安全屬性,設(shè)定為NULL的安全描述符;
    • 第二個(gè)表示設(shè)置信號(hào)復(fù)位方式為自動(dòng)恢復(fù)為無信號(hào)狀態(tài)(FALSE)還是手動(dòng)恢復(fù)為無信號(hào)狀態(tài)(TRUE),設(shè)為TRUE,因?yàn)楹竺鎽?yīng)用程序會(huì)重置事件消息;
    • 第三個(gè)是事件消息初始狀態(tài)的布爾值,為FALSE;
    • 最后一個(gè)是信號(hào)名稱,可以直接設(shè)置為NULL;

      3、打開Kinect設(shè)備的彩色圖像數(shù)據(jù)流

    //3、打開KINECT設(shè)備的彩色信息通道,并用colorStreamHandle保存該流的句柄,以便于以后讀取 hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, 0, 2, nextColorFrameEvent, &colorStreamHandle); if (FAILED(hr)) {cout << "Could not open color image stream video" << endl;NuiShutdown();return hr; }

    使用這個(gè)函數(shù)可以打開Kinect設(shè)備的彩色圖或是深度圖的訪問通道。也可以理解為,創(chuàng)建一個(gè)訪問彩色圖或深度圖的數(shù)據(jù)流。

    函數(shù)原型:

    _Check_return_ HRESULT NUIAPI NuiImageStreamOpen(_In_ NUI_IMAGE_TYPE eImageType,_In_ NUI_IMAGE_RESOLUTION eResolution,_In_ DWORD dwImageFrameFlags,_In_ DWORD dwFrameLimit,_In_opt_ HANDLE hNextFrameEvent,_Out_ HANDLE *phStreamHandle);

    參數(shù)說明:

  • eImageType:這是一個(gè)NUI_IMAGE_TYPE枚舉類型的變量,用來指定要?jiǎng)?chuàng)建的數(shù)據(jù)流的類型。比如,NUI_IMAGE_TYPE_COLOR對(duì)應(yīng)彩色圖,NUI_IMAGE_TYPE_DEPTH對(duì)應(yīng)深度圖。注意,這里指定的圖像的類型,必須是前面初始化是已經(jīng)指定過的,否則無法打開。
  • eResolution:這是一個(gè)NUI_IMAGE_RESOLUTION枚舉類型的變量,用來指定打開圖像的分別率,但是由于3D結(jié)構(gòu)光攝像頭與RGB攝像頭的分辨率不同,所以根據(jù)前面eImageType參數(shù)指定的圖像類型不同,這里也有所不同。如果eImageType指定為彩色圖NUI_IMAGE_TYPE_COLOR,那么就有兩種分辨率:NUI_IMAGE_RESOLUTION_1280x960、NUI_IMAGE_RESOLUTION_640x480;如果eImageType指定為深度圖NUI_IMAGE_TYPE_DEPTH,那么就有三種分辨率:NUI_IMAGE_RESOLUTION_640x480、NUI_IMAGE_RESOLUTION_320x240、NUI_IMAGE_RESOLUTION_80x60。
  • dwImageFrameFlags_NotUsed:看名字就知道了,沒有用到這個(gè)參數(shù),隨便給個(gè)數(shù)就可以了。
  • dwFrameLimit:指定NUI運(yùn)行時(shí)環(huán)境將要為你所打開的圖像類型建立幾個(gè)緩沖。最大值是NUI_IMAGE_STREAM_FRAME_LIMIT_MAXIMUM,即4。大多數(shù)程序中,定為2就足夠了。
  • hNextFrameEvent: 一個(gè)用來手動(dòng)重置信號(hào)是否可用的事件句柄(event),該信號(hào)用來控制Kinect是否可以開始讀取下一幀數(shù)據(jù)。也就是說在這里指定一個(gè)句柄后,隨著程序往后繼續(xù)運(yùn)行,當(dāng)你在任何時(shí)候想要控制kinect讀取下一幀數(shù)據(jù)時(shí),都應(yīng)該先使用WaitForSingleObject函數(shù)判斷一下該句柄,判斷是否有數(shù)據(jù)可拿。
  • phStreamHandle:函數(shù)執(zhí)行成功后,會(huì)創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)流,并讓這個(gè)句柄保存其地址。后面可以通過這個(gè)句柄來從Kinect讀取數(shù)據(jù)。
  • 返回值:S_OK表示成功。
  • 4、等待數(shù)據(jù)更新,若更新完成則進(jìn)行下一步;

    //4.1、無線等待新的數(shù)據(jù),等到就返回 if (WaitForSingleObject(nextColorFrameEvent, INFINITE) == 0) { ... }

    前面也提到了這個(gè)函數(shù),如果事件(對(duì)應(yīng)nextColorFrameEvent)有信號(hào),即有數(shù)據(jù),那么返回值為0,程序也會(huì)往下執(zhí)行;如果沒有數(shù)據(jù),就會(huì)等待。函數(shù)的第二個(gè)參數(shù)表示等待時(shí)間,單位為ms,這里設(shè)為INFINITE,表示一直等待。

    5、從數(shù)據(jù)流中拿出圖像數(shù)據(jù);

    //4.2、從剛才打開數(shù)據(jù)流的流句柄中得到該幀的數(shù)據(jù),讀取到的數(shù)據(jù)地址存于pImageFrame中 hr = NuiImageStreamGetNextFrame(colorStreamHandle, 0, &pImageFrame);

    colorStreamHandle為前面保存了Kinect設(shè)備的彩色信息通道的句柄,這個(gè)函數(shù)會(huì)從colorStreamHandle中取出RGB圖像數(shù)據(jù),并保存在pImageFrame中。第二個(gè)參數(shù),表示延時(shí)多久獲取數(shù)據(jù),直接取為0,就是不等待直接取數(shù)據(jù)。
    成功調(diào)用完這個(gè)函數(shù)之后,從Kinect捕獲到的一幀圖像,會(huì)保存在一個(gè)NUI_IMAGE_FRAME結(jié)構(gòu)體中,pImageFrame為指向那個(gè)結(jié)構(gòu)體的指針,其中包含了很多信息,如:圖像類型,分辨率,圖像緩沖區(qū),時(shí)間戳等等。

    6、提取數(shù)據(jù)幀并鎖定數(shù)據(jù);

    INuiFrameTexture * pTexture = pImageFrame->pFrameTexture; NUI_LOCKED_RECT LockedRect;//4.3、提取數(shù)據(jù)幀到LockedRect(它包括兩個(gè)數(shù)據(jù)對(duì)象:pitch每行字節(jié)數(shù),pBits第一個(gè)字節(jié)地址) //并鎖定數(shù)據(jù),這樣當(dāng)我們讀取數(shù)據(jù)的時(shí)候,kinect就不會(huì)去修改它 pTexture->LockRect(0, &LockedRect, NULL, 0);

    INuiFrameTexture是一個(gè)保存圖像幀數(shù)據(jù)的對(duì)象,主要要用到他的下面兩個(gè)共有方法:

    • LockRect:給緩沖區(qū)上鎖;
    • UnlockRect:給緩沖區(qū)解鎖;

    因?yàn)閳D像幀是保存在緩沖區(qū)的,如果不上鎖的話,緩沖區(qū)中還有的圖像可能會(huì)導(dǎo)致Kinect修改要取出的圖像。

    提取數(shù)據(jù)幀到LockedRect后,它包含兩個(gè)數(shù)據(jù)對(duì)象:pitch,每行字節(jié)數(shù);pBits,第一個(gè)字節(jié)地址。

    7、將數(shù)據(jù)轉(zhuǎn)換為OpenCV的Mat格式。

    //4.4、確認(rèn)獲得的數(shù)據(jù)是否有效 if (LockedRect.Pitch != 0) {//4.5、將數(shù)據(jù)轉(zhuǎn)換為OpenCV的Mat格式for (int i = 0; i < img.rows; i++){uchar *ptr = img.ptr<uchar>(i); //第i行的指針//每個(gè)字節(jié)代表一個(gè)顏色信息,直接使用ucharuchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;for (int j = 0;j < img.cols;j++){//內(nèi)部數(shù)據(jù)是4個(gè)字節(jié),0-1-2是BGR,第4個(gè)現(xiàn)在未使用ptr[3 * j] = pBuffer[4 * j];ptr[3 * j + 1] = pBuffer[4 * j + 1];ptr[3 * j + 2] = pBuffer[4 * j + 2];}}

    這一部分沒什么說的了,就是把LockedRect中的數(shù)據(jù)取出來,保存為OpenCV支持的Mat格式。

    參考資料

  • https://blog.csdn.net/zouxy09/article/details/8146266
  • https://blog.csdn.net/timebomb/article/details/7169372
  • 后記

    這個(gè)筆記總體來說不難,主要是套路,微軟官網(wǎng)的文檔早就撤了,畢竟用的還是Kinect v1.0的,靠著博客和看看源碼大概還能用用。
    前段時(shí)間直到最近感覺都挺多事情的,很多筆記和寫好的代碼都沒時(shí)間去整理,還要加把勁了。這段時(shí)間又有世界杯,熬夜看球什么的真的挺“傷”的。

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Kinect学习(三):获取RGB颜色数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。