RealSense SDK 开发笔记 (三)获取R200的图像(OpenCV Mat)

(转载请注明出处)
由于上合会议期间外面的快递无法到达市内,F200这些天多半是回不来了。。。这里写图片描述
然后就等着我写SR300的吧科科~
上一节的代码的目的是了解SDK的蛋疼,也对手里的摄像头信息有个了解,当我们熟(麻)悉(木)之后很多信息就没必要管了,这节实(不)用(再)为(装)主(哔~),获取R200的彩色、深度和红外帧的数据,转换成Mat类型并显示出来。


看代码吧,到手即用(逃):

查找设备(获取并初始化指定摄像头的Device接口)

这个函数可以和SenseManager配合使用。
初始化SenseManager里面的模块之后,得益于Intel的渣调教,我们不得不自己动手再调一下曝光啥的。

根据iuid查找:

PXCCapture::Device* RealSense::ImplSeek(pxcUID iuid)
{
    cout << "目标IUID:" << iuid << endl;
    PXCCapture *Capture;
    for (uint_fast8_t idx = 0; idx1)
    {
        PXCSession::ImplDesc Impl = {};
        Impl.group = PXCSession::IMPL_GROUP_SENSOR;
        Impl.subgroup = PXCSession::IMPL_SUBGROUP_VIDEO_CAPTURE;
        retStatus = Session->QueryImpl(&Impl, idx, &Impl);
        if (retStatus < PXC_STATUS_NO_ERROR)    continue;
        cout << "--------------------------------------------------------------------------------------"<"DCM服务:" <cout <<" *** IUID是:"<< Impl.iuid << endl;
        retStatus = Session->CreateImpl(&Impl, &Capture);
        if (retStatus < PXC_STATUS_NO_ERROR)    continue;
        dinfo = { 0 };
        retStatus = Capture->QueryDeviceInfo(idx, &dinfo);
        if (retStatus < PXC_STATUS_NO_ERROR) { cout << "详细信息:获取失败" << endl; continue; }
        wcout << "详细信息:" << endl;
        wcout << "  名称:" << dinfo.name << " 位于DCM设备索引 " << dinfo.didx << endl;
        wcout << "  可使用视频流:";
        if (dinfo.streams&PXCCapture::STREAM_TYPE_COLOR) cout << "COLOR ";
        if (dinfo.streams&PXCCapture::STREAM_TYPE_DEPTH) cout << "DEPTH ";
        if (dinfo.streams&PXCCapture::STREAM_TYPE_IR) cout << "IR ";
        if (dinfo.streams&PXCCapture::STREAM_TYPE_LEFT) cout << "LEFT" ;
        if (dinfo.streams&PXCCapture::STREAM_TYPE_RIGHT) cout << "RIGHT "; wcout << endl;
        wcout << "  固件版本:V" << dinfo.firmware[0] << "." << dinfo.firmware[1] << "." << dinfo.firmware[2] << "." << dinfo.firmware[3] <// 顺便检查一下是否要升级固件 
        wcout << "  序列号:" << dinfo.serial << endl; // 最终确定是哪个摄像机就靠它认了
        wcout << "  设备标识符:" << dinfo.did << endl;// 不嫌蛋疼的也可以拿它认
        if (Impl.iuid != iuid)  continue; 
        cout << "======================================================================================" << endl;
        wcout << "√!找到了匹配的" << Capture->DeviceModelToString(dinfo.model)<<" ";
        device = Capture->CreateDevice(idx);
        return device;
    }
    if (device == NULL) { cout << "\n没有匹配的设备,"; }
    return NULL;
}

暂时遇到一个问题:R200动不动就无法正常读出来信息(这几天解决)
被M$坑完再被Intel坑=_=|||

初始化视频流格式

void StreamInit(int Profile_idx, PXCCapture::Device *dstDevice, bool Dualeye)
{
    PXCCapture::Device::StreamProfileSet ProfileSet = {};
    if (Dualeye)
    {
        PXCCapture::StreamType scope = PXCCapture::STREAM_TYPE_COLOR | PXCCapture::STREAM_TYPE_DEPTH | PXCCapture::STREAM_TYPE_LEFT | PXCCapture::STREAM_TYPE_RIGHT;
        dstDevice->QueryStreamProfileSet(scope, Profile_idx, &ProfileSet);
        ProfileSet.color.options = ProfileSet.depth.options =
        ProfileSet.right.options = ProfileSet.left.options =
        PXCCapture::Device::STREAM_OPTION_STRONG_STREAM_SYNC;
    }
    else
    {
        PXCCapture::StreamType scope = PXCCapture::STREAM_TYPE_COLOR | PXCCapture::STREAM_TYPE_DEPTH | PXCCapture::STREAM_TYPE_IR;
        dstDevice->QueryStreamProfileSet(scope, Profile_idx, &ProfileSet);
        ProfileSet.color.options = ProfileSet.depth.options =
        ProfileSet.ir.options = 
        PXCCapture::Device::STREAM_OPTION_STRONG_STREAM_SYNC;
    }
    if (dstDevice->IsStreamProfileSetValid(&ProfileSet))
    {
        dstDevice->SetStreamProfileSet(&ProfileSet);
        cout << "Ready" << endl;
    }
    else
        cout << "Bad ProfileSet" << endl;
}
/*
@Profile_idx:根据上节查询的代码,找到对应的索引号即可
@*dstDevice:对应操作的设备
@Dualeye:是否是R200(我偷懒了,本应该自动判断的)
渣代码渣风格,建议自己写一遍
*/

获取帧数据

这里擅自写了一个结构体(浪费资源):

struct Frames
{
    Mat     Color;
    Mat     Depth;
    Mat     IR;
    Mat     IR_;
};

由于R200有两个红外帧,所以这里第四个是留给R200的。

默认只获取RGBD:

Frames Update(PXCCapture::Device *Device , bool Dualeye = true, PXCCapture::StreamType scope = PXCCapture::STREAM_TYPE_COLOR | PXCCapture::STREAM_TYPE_DEPTH)
{
    PXCCapture::Sample FrameSamples;
    PXCImage::ImageData color8, deth16, _ir,biol16, bior16;
    retStatus = Device->ReadStreams(scope, &FrameSamples);
    if (retStatus < PXC_STATUS_NO_ERROR) exit(0);// 有错直接退出
    Frames frames;
    if (Dualeye)
    {
        #pragma region dualeye
        if (scope & PXCCapture::STREAM_TYPE_COLOR)
        {
            FrameSamples.color->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_RGB24, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &color8);
            Mat Color(Size(320, 240), CV_8UC3, color8.planes[0]); frames.Color = Color;
            FrameSamples.color->ReleaseAccess(&color8);
        }
        if (scope & PXCCapture::STREAM_TYPE_DEPTH)
        {
            FrameSamples.depth->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_DEPTH, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &deth16);
            Mat Depth(Size(320, 240), CV_16UC1, deth16.planes[0]); frames.Depth = Depth;
            FrameSamples.depth->ReleaseAccess(&deth16);
        }
        if (scope & PXCCapture::STREAM_TYPE_LEFT)
        {
            FrameSamples.left->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_Y16, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &biol16);
            Mat StroL(Size(320, 240), CV_16UC1, biol16.planes[0]); frames.IR = StroL;
            FrameSamples.left->ReleaseAccess(&biol16);
        }
        if (scope & PXCCapture::STREAM_TYPE_RIGHT)
        {
            FrameSamples.right->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_Y16, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &bior16);
            Mat StroR(Size(320, 240), CV_16UC1, bior16.planes[0]); frames.IR_ = StroR;
            FrameSamples.right->ReleaseAccess(&bior16);
        }
        #pragma endregion
    }
    else
    {
        #pragma region _
        if (scope & PXCCapture::STREAM_TYPE_COLOR)
        {
            FrameSamples.color->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_RGB24, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &color8);
            Mat Color(Size(640, 480), CV_8UC3, color8.planes[0]); frames.Color = Color;
            FrameSamples.color->ReleaseAccess(&color8);
        }
        if (scope & PXCCapture::STREAM_TYPE_DEPTH)
        {
            FrameSamples.depth->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_DEPTH, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &deth16);
            Mat Depth(Size(640, 480), CV_16UC1, deth16.planes[0]); frames.Depth = Depth;
            FrameSamples.depth->ReleaseAccess(&deth16);
        }
        if (scope & PXCCapture::STREAM_TYPE_IR)
        {
            FrameSamples.ir->AcquireAccess(PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_Y16, PXCImage::ROTATION_0_DEGREE, PXCImage::OPTION_ANY, &_ir);
            Mat _IR(Size(640, 480), CV_16UC1, _ir.planes[0]); frames.IR = _IR;
            FrameSamples.left->ReleaseAccess(&_ir);
        }
        #pragma endregion
    }
    FrameSamples.ReleaseImages(); return(frames);
}

PXCCapture::Sample 这种结构体里面有名为:*color;*depth;*ir;left;*right;的PXCImage类型的变量:
对应彩色帧、深度帧、红外帧、双目左红外帧、双目右红外帧的图像数据描述和接口。用ReadStreams来获取StramType包含的类型的图像。
PXCImage::ImageData 这个类型是来描述图像存储信息的(像素格式,首地址,step)。
下面来看看获取图像内容的函数:
AcquireAccess:临时锁定要访问的帧内部数据,并将数据格式化成指定格式,然后告诉ImageData数据的存放信息。
ReleaseAccess:顾名思义,释放刚才锁定的数据内容。

把图像数据取出来:

OpenCV的一行代码即可,如彩色图:

Mat bgr(Size(r, c), CV_8UC3, color8.planes[0])

这里写图片描述暴力美学如上,而且Mat拷贝只是复制图像的头数据,时间损失很小。
重载用到的参数依次是Size(行,列)、图像类型、数据起始指针。step在这里是自动的,代表最高维度包含的字节数,图象是二维的,step有两级,一个是行字节数,一个是点字节数。


main函数

/* #define R200_IUID  自己填写 */
PXCSession *Session =PXCSession::CreateInstance(); 
pxcStatus retStatus;
int main()
{
    PXCCapture::Device *R200_Device;
    // Init Device
    R200_Device = ImplSeek(R200_IUID);
    StreamInit(6, R200_Device, true);
    cout << "Streaming..." << endl;
    // loop
    for (;;)
    {
        Frames R200_rgbd = Update(R200_Device);
        //pipeline
        Mat Depth8 = R200_rgbd.Depth.clone(); 
        (Depth8 /= 15).convertTo(Depth8, CV_8UC1, 1, 20);
        //show
        imshow("Depth8", Depth8);
        imshow("Color", R200_rgbd.Color);
        waitKey(1);
    }

程序截图:

RealSense SDK 开发笔记 (三)获取R200的图像(OpenCV Mat)_第1张图片

至于为什么不用SenseManager

直接看CPU占用率(相同帧率、分辨率):
上述代码:
RealSense SDK 开发笔记 (三)获取R200的图像(OpenCV Mat)_第2张图片
使用sensemanager的示例程序:
这里写图片描述
SenseManager给DCM喂了金克拉了?这么吃资源…
8逻辑核i7,可见单核心使用率过半,低压U的流畅度估计好不到哪去。
RealSense SDK 开发笔记 (三)获取R200的图像(OpenCV Mat)_第3张图片
用了SenseManager的程序关了之后,经常枚举设备信息失败,时不时卡在提交流格式的函数上。
DCM驱动渣,优化渣,不过配上自己的渣算法这点资源损失并不算什么(雾)
等情况足够复杂再用吧。

你可能感兴趣的:(RealSense,SDK)