近期,需要把PCL的点云格式转换成tiff格式的图片,然后在halcon中处理。
总结转换过程如下
1. 转换函数(C++代码)
主要思路:
- 使用了libtiff库,来写tiff格式
- 把点云的x,y,z通道转换成tiff格式图片的三通道。
- 所以后续读取tiff格式图片转换成点云时,注意三通道代表x,y,z的顺序
- 写tiff格式的时候就是设置文件头,然后把数据一个字节一个字节的写进去
函数说明:
- pointcloud2tiff()是主要的转换函数,把PCL的点云数据cloud,写到filename文件中去
- main()写了调用示例,读取"test_tif.ply"点云文件,转换成tiff格式,写到"test.tif"文件中去
#include <iostream>
#include <pcl/io/ply_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <string>
#include "tiffio.h"
using namespace std;
void pointcloud2tiff(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud, const std::string filename)
{
TIFF *out = TIFFOpen(filename.c_str(), "w");
int sampleperpixel = 3; // x, y, z
int bitspersample = 32; //float
int width = cloud->width;
int height = cloud->height;
float *image = new float[width*height*sampleperpixel];
int linesamples = sampleperpixel * width;
int linebytes = linesamples * sizeof(float);
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
image[r*(linesamples)+3 * c + 0] = (*cloud)(c, r).x;
image[r*(linesamples)+3 * c + 1] = (*cloud)(c, r).y;
image[r*(linesamples)+3 * c + 2] = (*cloud)(c, r).z;
}
}
// set header
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); // set the width of the image
TIFFSetField(out, TIFFTAG_IMAGELENGTH, height); // set the height of the image
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, sampleperpixel); // set number of channels per pixel
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bitspersample); // set the size of the channels
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); // set the origin of the image.
// Some other essential fields to set that you do not have to understand for now.
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
unsigned char *buf = NULL;
if (TIFFScanlineSize(out)) {
buf = (unsigned char *)_TIFFmalloc(linebytes);
}
else {
buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
}
// We set the strip size of the file to be size of one row of pixels
TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, width*sampleperpixel));
//Now writing image to the file one strip at a time
for (int row = 0; row < height; row++) {
//memcpy(buf, &image[(height - row - 1)*linebytes], linebytes * sizeof(float));
memcpy(buf, &image[row*linesamples], linebytes);
if (TIFFWriteScanline(out, buf, row, 0) < 0) {
fprintf(stderr, "scanline %d: Write error.\n", row);
break;
}
}
TIFFClose(out);
if (buf) {
_TIFFfree(buf);
}
if (image) {
delete[]image;
}
}
int main()
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPLYFile<pcl::PointXYZRGB>("test_tif.ply", *cloud);
pointcloud2tiff(cloud, "test.tif");
return 0;
}
2. 其他说明
2.1 libtiff库
libtiff库的安装使用,可参考官网 http://www.libtiff.org/
按照说明,编译安装即可。
使用的时候建议用cmake来配置
2.2 扩展说明
- 上面的代码是把x,y,z通道保存到tif中去,如果需要把r,g,b等其他信息也保存进去,注意
sampleperpixel
和tiff文件头的设置 - 根据上面的代码,可以不限于PCL的点云格式,只要把相应的x,y,z信息填进去即可转换成tiff
网友评论