在OpenCV中,有一种数据结构是Mat,我们一般会定义一个frame的变量,这个变量可以是4通道的,也可以说3通道的。
前不久在一个项目中遇到了这个问题,要求是用ZED相机来实时拍摄视频并实时显示。ZED相机中的Mat是4通道的,虽然也可以调用3通道的模式,但是调用3通道的模式有问题。如果将ZED中sl转化成OpenCV格式后的image_ocv直接转换成3通道模式的话,会导致预览窗口只有一帧画面卡死,不会连续采集图像。所以将ZED相机中的sl::Mat结构(image_zed)先变成OpenCV的Mat结构(image_ocv),然后赋值给OpenCV中的Mat(frame),然后再将frame转换成3通道的,就就可以实现实时采集视频了。
代码如图:
下图是OpenCV中的Mat,命名frame
下图是将ZED相机中sl的Mat,命名image_zed,然后转化成OpenCV格式的Mat:image_ocv
先将image_ocv转换成frame,然后将frame变成3通道。这样不会出问题,如果将image_ocv先转换成三通道,而后赋值给frame,会只显示一帧画面。
frame = image_ocv;
//四通道->三通道
cvtColor(frame, frame, COLOR_RGBA2RGB);
下面是部分代码:
// To share data between sl::Mat and cv::Mat, use slMat2cvMat()
// Only the headers and pointer to the sl::Mat are copied, not the data itself
sl::Mat image_zed(new_width, new_height, sl::MAT_TYPE::U8_C4);
cv::Mat image_ocv = slMat2cvMat(image_zed);
#ifndef HAVE_CUDA // If no cuda, use CPU memory
sl::Mat depth_image_zed(new_width, new_height, sl::MAT_TYPE::U8_C4);
cv::Mat depth_image_ocv = slMat2cvMat(depth_image_zed);
#else
Mat depth_image_zed_gpu(new_width, new_height, MAT_TYPE::U8_C4, sl::MEM::GPU); // alloc sl::Mat to store GPU depth image
cv::cuda::GpuMat depth_image_ocv_gpu = slMat2cvMatGPU(depth_image_zed_gpu); // create an opencv GPU reference of the sl::Mat
cv::Mat depth_image_ocv; // cpu opencv mat for display purposes
#endif
char key = ' ';
while (1) {
// A new image is available if grab() returns SUCCESS
if (zed.grab(runtime_parameters) == sl::ERROR_CODE::SUCCESS) {
// Retrieve left image
zed.retrieveImage(image, sl::VIEW::LEFT);
// Retrieve depth map. Depth is aligned on the left image
zed.retrieveMeasure(depth, sl::MEASURE::DEPTH);
// Retrieve colored point cloud. Point cloud is aligned on the left image.
zed.retrieveMeasure(point_cloud, sl::MEASURE::XYZRGBA);
// Retrieve the left image, depth image in half-resolution
zed.retrieveImage(image_zed, sl::VIEW::LEFT, sl::MEM::CPU, new_image_size);
#ifndef HAVE_CUDA
// retrieve CPU -> the ocv reference is therefore updated
zed.retrieveImage(depth_image_zed, sl::VIEW::DEPTH, sl::MEM::CPU, new_image_size);
#else
// retrieve GPU -> the ocv reference is therefore updated
zed.retrieveImage(depth_image_zed_gpu, VIEW::DEPTH, MEM::GPU, new_image_size);
#endif
// Retrieve the RGBA point cloud in half-resolution
// To learn how to manipulate and display point clouds, see Depth Sensing sample
zed.retrieveMeasure(point_cloud, sl::MEASURE::XYZRGBA, sl::MEM::CPU, new_image_size);
//显示相机信息
if (display_map)
{
cv::imshow("Image", image_ocv);
//cv::waitKey(30);
}
#ifdef HAVE_CUDA
// download the Ocv GPU data from Device to Host to be displayed
depth_image_ocv_gpu.download(depth_image_ocv);
#endif
if (display_depth)
{
cv::imshow("Depth", depth_image_ocv);
//cv::waitKey(30);
}
frame = image_ocv;
//四通道->三通道
cvtColor(frame, frame, COLOR_RGBA2RGB);