再度開啟Kinect_深度影像分析



這次的研究





針對於opencv套用在Kinect v2 SDK 的深度影像呈現方式


我們已經很清楚知道Kinect 在處理 frame 數據的先後流程為




「傳感器」獲得「源」
「源」打開「閱讀器」
「閱讀器」獲得「視訊(frame)」
(ps: 幀」   讀作 ㄓㄥˋ 計算照片、字畫、影像等單位,也就是frame)







【程式碼】


#include <iostream>
#include <opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\video\background_segm.hpp>
#include <Kinect.h>

using namespace std;
using namespace cv;

// Safe release for interfaces
template<class Interface>
inline void SafeRelease(Interface *& pInterfaceToRelease)
{
    if (pInterfaceToRelease != NULL)
    {
        pInterfaceToRelease->Release();
        pInterfaceToRelease = NULL;
    }
}

int main()
{
    //取得sensor
    IKinectSensor* pSensor;//處理Kinect v2的Sensor接口
    HRESULT hResult = S_OK;
    hResult = GetDefaultKinectSensor(&pSensor);//取得預設的Sensor
    if (FAILED(hResult))
    {
        cerr << " Error : GetDefaultKinectSensor " << endl;
        return -1;
    }
    hResult = pSensor->Open();//打開Sensor 
    if (FAILED(hResult))
    {
        cerr << " Error : IKinectSensor::Open() " << endl;
        return -1;
    }

    //從「Sensor」取得「Source」
    IDepthFrameSource* pDepthSource;//取得Depth Frame的Source接口
    hResult = pSensor->get_DepthFrameSource(&pDepthSource);//從Sensor取得Source
    if (FAILED(hResult))
    {
        cerr << " Error : IKinectSensor::get_DepthFrameSource() " << endl;
        return -1;
    }

    //從「Source」打開「Reader」
    IDepthFrameReader* pDepthReader;//取得Depth Frame的Reader接口
    hResult = pDepthSource->OpenReader(&pDepthReader);//從Source打開Reader
    if (FAILED(hResult))
    {
        cerr << " Error : IDepthFrameSource::OpenReader() " << endl;
        return -1;
    }

    //從「Reader」取得最新的「Frame」
    int width = 512;
    int height = 424;
    unsigned int bufferSize = width * height * sizeof (unsigned short);
    Mat bufferMat(height, width, CV_16SC1);//每個pixel佔16位元,有正負號,因為16位元有正負號所以用char表示pixel,每個pixel有一個channel
    Mat depthMat(height, width, CV_8UC1);//每個pixel佔8位元,無正負號,因為8位元無正負號所以用char表示pixel,每個pixel有一個channel
    namedWindow(" Depth ");
    while (1){
        // Frame 
        IDepthFrame* pDepthFrame = nullptr; 
            hResult = pDepthReader->AcquireLatestFrame(&pDepthFrame);
        if (SUCCEEDED(hResult)){
            hResult = pDepthFrame->AccessUnderlyingBuffer(&bufferSize, reinterpret_cast<UINT16**>(&bufferMat.data));
            if (SUCCEEDED(hResult)){
                //bufferMat.convertTo(depthMat, CV_8U,  255.0f / 4500.0f );   //255.0/4500.0 = 0.0566666
                //bufferMat.convertTo(depthMat, CV_8U, 0.005);//有點黑
                //bufferMat.convertTo(depthMat, CV_8U, 0.05);//變亮了
                //bufferMat.convertTo(depthMat, CV_8U, 0.5);//變超白
                //bufferMat.convertTo(depthMat, CV_8U, 0.1);//白背景灰身體
                //bufferMat.convertTo(depthMat, CV_8U, 0.2);//白背景淡灰身體
                bufferMat.convertTo(depthMat, CV_8U, 0.3);//白背景白身體
                //原Mat.convertTo(輸出Mat, int rtype, double alpha=1, double beta=0 );
            }
        }
        SafeRelease(pDepthFrame);
        // Show Window 
        cv::imshow(" Depth " , depthMat);
        if (cv::waitKey(30) == VK_ESCAPE){
            break;
        }
    }


    return 0;
}



這裡我要介紹一個   opencv 的 特殊函數

叫做「  .convertTo( ) 」

void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;

原先的Mat格式的變數轉換為另一種數據格式存儲到輸出矩陣m中,如果m的格式或大小不正確則會重新創建.rtype為轉換后的類型,如果為負數,則與原Mat相同.這個函數可以對其中的值進行縮放和偏移,公式為 m(x,y)=newtype((alpha*src(x,y)+beta))



如果你對這個函數 -->右鍵-->查看定義

他會跟你說
converts matrix to another datatype with optional scalng. See cvConvertScale.



為了處理Depth數據而準備的OpenCV的cv::Mat類型

「bufferMat」是16bit的原始的Depth數據,
「depthMat」為了作為圖像顯示,把Depth數據儲存到8bit的範圍裡的處理。

 「CV_16UC1」,是把無符號16bit整數(16U) 放入1個channel(C1)
並列來表現1個像素的數據格式。

 「CV_8UC1」,是表現無符號8bit整數 (8U)的數據格式。

Kinect V2 Depth Image架構示意圖














Depth數據的排列
一個pixel 佔16 bit






得到「Frame」,就可以把取出Depth數據,作成圖像來可視化。

取出的Depth數據,像圖3一樣以16bit(0~4500)為1像素來構成。
因為這樣的圖像不能顯示

(注:OpenCV只能顯示8bit的圖像數據)

所以我們才需要把格式轉化為8bit(0~255)的範圍。

這裡我使用cv::Mat的轉換函數(cv::Mat::convertTo())

把離傳感器距離近的顯示很白(255),遠的顯示為很黑(0)的方式來轉化。



把離傳感器距離近的顯示很黑(0),遠的顯示為很白(255)的方式來轉化。




其他還有很多種  double 的 參數可以試試看   看出來效果




















本次分析
告一段落



留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題