將 pcd 檔轉換成深度圖與 RGB 圖檔
發表於
當我們好不容易產生了一個 pcd 模型後,突然發現到忘記儲存原始的 RGB 影像以及深度影像, 這個時候要怎辦呢?你可以選擇重新使用 kinect 建立新的模型並拍下影像以及深度,也可以用 更聰明的方法 - 將 pcd 檔案轉換成 RGB 影像以及深度影像。
實際上,在 pcl 1.7 版提供了以下方法,讓你可以將 point cloud 存成 PNG 文件。
void pcl::io::savePNGFile (const std::string &file_name, const pcl::PointCloud< T > &cloud);
但是如果我們使用的是 pcl 1.6 或者以下的版本呢?這時候就得手動增加這部份的 code。
template <typename T>
void savePNGFile (const std::string &file_name, const pcl::PointCloud<T> &cloud)
{
std::vector<unsigned char> char_data(cloud.width * cloud.height * 3);
for (size_t i = 0; i < cloud.points.size(); ++i) {
char_data[i*3 + 0] = cloud.points[i].r;
char_data[i*3 + 1] = cloud.points[i].g;
char_data[i*3 + 2] = cloud.points[i].b;
}
vtkSmartPointer<vtkImageImport> importer = vtkSmartPointer<vtkImageImport>::New();
importer->SetNumberOfScalarComponents(3);
importer->SetDataScalarTypeToUnsignedChar();
importer->SetWholeExtent (0, cloud.width - 1, 0, cloud.height - 1, 0, 0);
importer->SetDataExtentToWholeExtent();
void* data = const_cast<void*> (reinterpret_cast<const void*> (&char_data[0]));
importer->SetImportVoidPointer(data, 1);
importer->Update();
vtkSmartPointer<vtkImageFlip> flipYFilter = vtkSmartPointer<vtkImageFlip>::New();
flipYFilter->SetFilteredAxis(1);
flipYFilter->SetInputConnection(importer->GetOutputPort());
flipYFilter->Update();
vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
writer->SetFileName(file_name.c_str());
writer->SetInputConnection(flipYFilter->GetOutputPort());
writer->Write();
}
使用上面的程式碼,你就可以在 pcl 1.6 中將你的 point cloud 存成 png 圖片。
現在我想要將我的點雲轉變成為深度圖檔,這時該怎麼辦呢?你可以用下面的程式完成他:
template <typename T>
void saveDepthToPNG (const std::string &file_name, const pcl::PointCloud<T> &cloud)
{
pcl::PointCloud<T> depth = cloud;
double max = 0, min = 0;
for (int i = 0; i < (int) depth.points.size(); i++) {
if(depth.points[i].z > max) max = depth.points[i].z;
if(depth.points[i].z < min) min = depth.points[i].z;
}
float scale = (max - min) / 256;
for (int i = 0; i < (int) depth.points.size(); i++) {
unsigned int t = depth.points[i].z / scale;
// make sure pixel value between 0 ~ 255
t = (t > 255) ? 255 : (t < 0) ? 0 : t;
depth.points[i].rgba = ((t << 16) | (t << 8) | t);
}
savePNGFile(file_name, depth);
}
這個程式透過範圍的計算,將深度轉換成 0 ~ 255 的灰階值, 並將顏色塗到點雲上面, 最後再將點雲存檔成為 png 圖檔。
透過這樣的簡單步驟,我們就可以將 pcd 檔案轉換成為 RGB 彩圖 與 深度圖了。
下面列出簡單的主程式與結果
#include <iostream>
#include <string>
#include <cmath>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
typedef pcl::PointXYZRGBA PointT;
int main(int argc, char *argv[])
{
std::string pcd_file("room.pcd");
pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
pcl::io::loadPCDFile(pcd_file, *cloud);
// save origin pcd file to png pictre
std::string rgb_file("room.png");
savePNGFile(rgb_file, *cloud);
// save depth image
std::string depth_file("room_depth.png");
saveDepthToPNG(depth_file, *cloud);
return 0;
}
透過這個程式,你就可以將 room.pcd 轉換成以下兩張圖形
RGB 彩圖

深度圖
