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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

前言

在前面的文章中介紹了如何搭建Kinect開發環境:Kinect學習(一):開發環境搭建。搭建好環境后,首先要做的當然就是試著讀取Kinect中的數據了。

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

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

代碼

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

#include <windows.h> #include <NuiApi.h> #include <iostream> #include <opencv2/opencv.hpp>/* 幾個常用的頭文件: 1、NuiApi.h ---包含所有的NUI(自然用戶界面) API頭文件和定義基本的初始化和函數訪問入口。這是我們C++工程的主要頭文件,它已經包含了NuiImageCamera.h 和 NuiSkeleton.h。 2、NuiImageCamera.h ---定義了圖像和攝像頭服務的API,包括調整攝像頭的角度和仰角,打開數據流和讀取數據流等。 3、NuiSkeleton.h ---骨架有關的API,包括使能骨架跟蹤,獲取骨架數據,骨架數據轉換和平滑渲染等。 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、定義事件句柄//創建讀取下一幀的信號事件句柄,控制KINECT是否可以開始讀取下一幀數據HANDLE nextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);HANDLE colorStreamHandle = NULL;//保存圖像數據流的句柄,用于提取數據//3、打開KINECT設備的彩色信息通道,并用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、開始讀取彩色圖數據while (1){const NUI_IMAGE_FRAME * pImageFrame = NULL;//4.1、無線等待新的數據,等到就返回if (WaitForSingleObject(nextColorFrameEvent, INFINITE) == 0){//4.2、從剛才打開數據流的流句柄中得到該幀的數據,讀取到的數據地址存于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、提取數據幀到LockedRect(它包括兩個數據對象:pitch每行字節數,pBits第一個字節地址)//并鎖定數據,這樣當我們讀取數據的時候,kinect就不會去修改它pTexture->LockRect(0, &LockedRect, NULL, 0);//4.4、確認獲得的數據是否有效if (LockedRect.Pitch != 0){//4.5、將數據轉換為OpenCV的Mat格式for (int i = 0; i < img.rows; i++){uchar *ptr = img.ptr<uchar>(i); //第i行的指針//每個字節代表一個顏色信息,直接使用ucharuchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;for (int j = 0;j < img.cols;j++){//內部數據是4個字節,0-1-2是BGR,第4個現在未使用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、這幀已經處理完了,所以將其解鎖pTexture->UnlockRect(0);//6、釋放本幀數據,準備獲取下一幀NuiImageStreamReleaseFrame(colorStreamHandle, pImageFrame);}if (cv::waitKey(20) == 27)break;}//7、關閉NUI連接NuiShutdown();return 0; }

運行結果

說明

整個程序可以分為以下流程:

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

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

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

    HRESULT NuiInitialize(DWORD dwFlags);

    dwFlags表示標志位,有以下幾種情況:

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

    以上的都各自對應一個標志位,使用時可以使用|將它們組合起來。

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

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

    或者判斷是否等于S_OK:

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

    2、定義事件句柄

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

    該函數會創建一個windows事件對象,創建成功則返回事件的句柄。這里的這個事件是用來判斷是否有新數據的。
    其中有四個參數:

    • 第一個是安全屬性,設定為NULL的安全描述符;
    • 第二個表示設置信號復位方式為自動恢復為無信號狀態(FALSE)還是手動恢復為無信號狀態(TRUE),設為TRUE,因為后面應用程序會重置事件消息;
    • 第三個是事件消息初始狀態的布爾值,為FALSE;
    • 最后一個是信號名稱,可以直接設置為NULL;

      3、打開Kinect設備的彩色圖像數據流

    //3、打開KINECT設備的彩色信息通道,并用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; }

    使用這個函數可以打開Kinect設備的彩色圖或是深度圖的訪問通道。也可以理解為,創建一個訪問彩色圖或深度圖的數據流。

    函數原型:

    _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);

    參數說明:

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

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

    前面也提到了這個函數,如果事件(對應nextColorFrameEvent)有信號,即有數據,那么返回值為0,程序也會往下執行;如果沒有數據,就會等待。函數的第二個參數表示等待時間,單位為ms,這里設為INFINITE,表示一直等待。

    5、從數據流中拿出圖像數據;

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

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

    6、提取數據幀并鎖定數據;

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

    INuiFrameTexture是一個保存圖像幀數據的對象,主要要用到他的下面兩個共有方法:

    • LockRect:給緩沖區上鎖;
    • UnlockRect:給緩沖區解鎖;

    因為圖像幀是保存在緩沖區的,如果不上鎖的話,緩沖區中還有的圖像可能會導致Kinect修改要取出的圖像。

    提取數據幀到LockedRect后,它包含兩個數據對象:pitch,每行字節數;pBits,第一個字節地址。

    7、將數據轉換為OpenCV的Mat格式。

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

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

    參考資料

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

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

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

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。