深度图从ros数据类型转换成了opencv数据类型

Posted cv_gordon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度图从ros数据类型转换成了opencv数据类型相关的知识,希望对你有一定的参考价值。

摘要:ros下,利用realsense D435采集深度图,并将其转换成opencv的数据类型。

 

一. RGBD图像采集

通过image_transport包,根据给定的采集速度从realsense D435发布的topic中订阅深度图的代码。

void depth_Callback(const sensor_msgs::ImageConstPtr& depth_msg)
{
  cv_bridge::CvImagePtr depth_ptr;
  try
  {
    //cv::imshow("depth_view", cv_bridge::toCvShare(depth_msg, sensor_msgs::image_encodings::TYPE_16UC1)->image);
    //depth_ptr = cv_bridge::toCvCopy(depth_msg, sensor_msgs::image_encodings::TYPE_16UC1); 
    cv::imshow("depth_view", cv_bridge::toCvShare(depth_msg, sensor_msgs::image_encodings::TYPE_32FC1)->image);
    depth_ptr = cv_bridge::toCvCopy(depth_msg, sensor_msgs::image_encodings::TYPE_32FC1); 

    cv::waitKey(1000);
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from \'%s\' to \'32fc1\'.", depth_msg->encoding.c_str());
  }

}

在main函数中,

image_transport::ImageTransport it(nh);
image_transport::Subscriber sub1 = it.subscribe("/camera/aligned_depth_to_color/image_raw", 1, depth_Callback);

如代码所示,在ros中采集到的深度图是ros自带的数据类型sensor_msgs::image。如果要利用opencv对该深度图像进行操作,则需要转换成opencv的图像数据类型Mat,这一步转换操作通过cv_bridge完成。

 

在上述代码中, sensor_msgs::image_encodings::TYPE_16UC1 表示将ros数据类型转换cv数据类型的编码方式。一般而言,深度图的编码方式都有8UC, 16UC1, 32FC1等三种。在我们的程序中,如何判断选用哪种编码方式呢?最好的方法就是,深度图转换成cv数据类型后将深度值print出来,以此选定最佳的编码方式。

 

二. 读取深度值

深度图转换成opencv的数据类型后,需要读取其中的深度值。这里着重介绍opencv矩阵元素的操作方法。

opencv中矩阵元素值的读取方法,转自https://blog.csdn.net/u011028345/article/details/73185166

1, 利用at函数读取

(1)单通道图像读取

Mat img1 = imread(filename,IMREAD_GRAYSCALE);  
   for( size_t nrow = 0; nrow < img1.rows; nrow++)  
   {  
       for(size_t ncol = 0; ncol < img1.cols; ncol++)  
       {  
           uchar val = mat_CV_8UC1.at<uchar>(nrow,ncol);      
       }  
   }

(2)三通道图像读取

Mat img2 = imread(filename,IMREAD_COLOR);  
   for( size_t nrow = 0; nrow < img2.rows; nrow++)  
    {  
       for(size_t ncol = 0; ncol < img2.cols; ncol++)  
       {  
           Vec3i bgr = mat_CV_8UC3.at<Vec3b>(nrow,ncol);//用Vec3b也行  
           cout   << "("<<bgr.val[0]<<","  
                   <<bgr.val[1]<<","  
                   <<bgr.val[2]<<")";  
       }  
       cout << endl;  
    }  

2, 使用指针读取

for( size_t nrow = 0; nrow < img3.rows; nrow++)  
    {  
        uchar* data = img3.ptr<uchar>(nrow);  
       for(size_t ncol = 0; ncol < img3.cols * img3.channels(); ncol++)  
       {  
            cout << int( data[ncol] ) ;  
       }  
       cout << endl;  
    }  

3, 使用迭代器

Mat img4 = imread(filename,IMREAD_GRAYSCALE);
MatIterator_<uchar> it = img4.begin<uchar>(), it_end = img4.end<uchar>();  
   for(int cnt = 1; it != it_end; ++it)  
    {  
        cout << ( int(*it) ) ;  
        if( (cnt++ % img4.cols) ==0 )  
            cout << endl;       
    }  

4, 使用矩阵元素的地址定位

Mat img5(rows, cols,CV_8U, Scalar(0));
for( size_t nrow = 0; nrow < img5.rows; nrow++)  
for(size_t ncol = 0; ncol < img5.cols; ncol++)
    {  
       cout<<(int)(*(img5.data+img5.step[0]*nrow+img5.step[1]*ncol));
    } 

 

5, 补充:在使用 at 函数的情况下需要预先知道Mat变量中存储的元素类型,如果类型不匹配就会出现读错误。所以可以采用c++  boost库中的BOOST_TYPEOF来获取图像的元素数据类型。

Mat img6 = imread(filename);
typedef BOOST_TYPEOF(*img6.data) ElementType
for( size_t nrow = 0; nrow < img1.rows; nrow++)  
   {  
       for(size_t ncol = 0; ncol < img1.cols; ncol++)  
       {  
        cout<<mat_CV_8UC1.at<ElementType>(nrow,ncol);      
       }  
   } 

 

关于如何判断opencv矩阵元素的数据类型,方法转自https://www.jianshu.com/p/204f292937bb

cv::Mat 类的对象有一个成员函数 type() 用来返回矩阵元素的数据类型,返回值是 int类型,不同的返回值代表不同的类型。OpenCV Reference Manual 中对 type() 的解释如下所示:

Mat::type
C++: int Mat::type() const
The method returns a matrix element type. This is an identifier compatible with the CvMat type system, like CV_16SC3 or 16-bit signed 3-channel array, and so on.

以本例的深度图为,

int pic_type = depth_ptr->image.type();
std::cout << "the element type of depth_pic is " << pic_type << std::endl;

从type()函数返回一个整数值,下一步就是查找返回值和具体类型之间的对应关系。

 

OpenCV中定义的图像数据类型可以由以下公式给出,

CV_<bit-depth>{U|S|F}C(<number_of_channels>).

其中,U为无符号整数,S为有符号整数,F为浮点数。

注意事项:

so CV_8UC3 is an 8-bit unsigned integer matrix/image with 3 channels. Although it is most common that this means an RGB (or actually BGR) image, it does not mandate it. It simply means that there are three channels, and how you use them is up to you and your application.

 

OpenCV常用的6种数据类型缩写

b = unsigned char,    8 bit    [0~255]

w = unsigned short,  16 bit  [0~65535]

s = short,                   16 bit [-32768~32767]

i = int

f = float

d = double

以上是关于深度图从ros数据类型转换成了opencv数据类型的主要内容,如果未能解决你的问题,请参考以下文章

图像位深度 8位 16位 24位 32位区别对比 RGB 真彩色 基本概念:(大小,深度,通道)位深度数据类型转换原理 Mat数据读取(opencv里的imread)

PCL数据类型和ROS数据类型的转换

opencv编程中cvMat到Mat如何进行数据转换?

Python中的强制类型转换函数int()和float()究竟把数据转换成了哪种整型哪种浮点型(这是个伪命题,Python的数值型数据类型只有四种)

PostgreSQL - 怎么转换数据类型

opencv的img.flat的函数用法