相关资料
kinect相机官方文档:https://learn.microsoft.com/en-us/previous-versions/azure/kin...
sdk文档:https://microsoft.github.io/Azure-Kinect-Sensor-SDK/master/in...
硬件属性
组成
相机拥有depth camera、color camera(RGB camera)、IR emitters、gyroscope、accelerometer和microphone多个传感器。本次学习只使用了其中的深度图相机和颜色相机。
深度相机和颜色相机的视场
深度相机视场有两个模式, 分别是norrow field of view和wide field of view,如下图所示。
下图是2000mm处拍摄的不同模式的图像范围的对比,所以如果进行depth image和color image的坐标转换可能有些坐标无法转换。
多相机同步
相机通过耳机线同步数据,其有两个3.5mm耳机孔:sync in和sync out
kinect有两种同步相机的拓扑结构:
- Daisy-chain configuration
相机连成链状,最多支持8台子设备。 - Star configuration
主相机输出线分成两股,也只最多支持2台子设备。
相机坐标系
2D坐标系
kinect输出的2d图像x方向构成了图像的width,y方向构成了图像的height,像素单元在内存中按先x后y的顺序存放,不同图像的像素构成不同。
3D坐标系
SDK简介
简单介绍下常用的方法。
static
// 获取当前设备个数
static uint32_t k4a::device::get_installed_count()
class device
// 根据特定配置打开相机,打开后相机会开始拍照,通过stop_cameras关闭
void start_cameras(const k4a_device_configuration_t *configuration)
// 获取当前设备序列号
std::string get_serialnum () const
// 捕获图像,其中cap为输出参数,可通过cap获取捕获到的图像
bool k4a::device::get_capture(capture *cap, std::chrono::milliseconds timeout)
// 获取相机标定参数
k4a::calibration k4a::device::get_calibration(k4a_depth_mode_t depth_mode,
k4a_color_resolution_t color_resolution) const
class capture
// 获取捕获到的各种图像
k4a::image k4a::capture::get_color_image () const
k4a::image k4a::capture::get_depth_image () const
k4a::image k4a::capture::get_ir_image () const
class image
// 获取图像宽/高
int k4a::image::get_width_pixels () const
int k4a::image::get_height_pixels () const
// 获取步长字节,这里的步长指的是在x方向像素的字节长度
int k4a::image::get_stride_bytes () const
// 获取图像流/长度
const uint8_t* k4a::image::get_buffer () const
size_t k4a::image::get_size () const
不同图像字节流像素结构
!注意3d和2d的像素按线性顺序对应
图像类型 | 像素大小 | 像素组成 |
---|---|---|
RGBA图像 | 4*1字节,类型为uint8 | 依次为Blue, Green, Red, Alpha |
点云图像 | 3*2字节,类型为int16 | 依次为x坐标,y坐标,z坐标 |
class calibration
calbration类提供了一些方法进行depth camera和rgb camera之间的坐标系转换
// 将源相机2d坐标系的坐标转化为目标相机2d坐标系坐标, target_point2d为输出参数
bool k4a::calibration::convert_2d_to_2d(const k4a_float2_t &source_point2d,
float source_depth,
k4a_calibration_type_t source_camera,
k4a_calibration_type_t target_camera,
k4a_float2_t *target_point2d) const
// ..其它方法类似
class transformation
该类提供了将不同坐标系下的图像进行转化的方法,输入输出都是图像,默认通过GPU加速
// 将color image的像素点通过坐标转换到depth camera坐标系上
k4a::image k4a::transformation::color_image_to_depth_camera(const image &depth_image, const image &color_image) const
// 将depth image的像素点通过坐标转换到color camera坐标系上
k4a::image k4a::transformation::depth_image_to_color_camera(const image &depth_image) const
// 将深度图像转化为点云图像,其中camera参数要指明当前深度图所在的坐标系是color坐标系还是depth坐标系
k4a::image k4a::transformation::depth_image_to_point_cloud(const image &depth_image, k4a_calibration_type_t camera) const
下图展示了depth camera和rgb camera在2d和3d坐标系下的转换方法
编写代码,生成点云图
struct Image {
k4a::image color;
k4a::image depth;
k4a::image depth_in_color;
};
struct Voxel {
int16_t x, y, z;
uint8_t r, g, b, a;
};
class Camera {
public:
Camera();
~Camera();
Image get_image();
std::vector<Voxel> generate_point_cloud(Image &image) const;
static void save_ply_file(const std::string& filename, const std::vector<Voxel>& points);
private:
k4a::device device_;
k4a::calibration calibration_{};
k4a::transformation transformation_;
};
#include <fstream>
#include "Camera.h"
Camera::Camera() {
uint32_t num = k4a::device::get_installed_count();
if (num <= 0) {
std::cout << "no device" << std::endl;
return;
}
device_ = k4a::device::open(0);
k4a_device_configuration_t config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
config.camera_fps = K4A_FRAMES_PER_SECOND_15;
config.depth_mode = K4A_DEPTH_MODE_WFOV_UNBINNED;
config.color_format = K4A_IMAGE_FORMAT_COLOR_BGRA32;
config.color_resolution = K4A_COLOR_RESOLUTION_3072P;
config.synchronized_images_only = true;
device_.start_cameras(&config);
calibration_ = device_.get_calibration(config.depth_mode, config.color_resolution);
transformation_ = k4a::transformation(calibration_);
}
Camera::~Camera() {
device_.stop_cameras();
device_.close();
}
Image Camera::get_image() {
k4a::capture cap;
bool result = device_.get_capture(&cap);
if (!result) {
throw std::runtime_error("get capture error");
}
Image image;
image.color = cap.get_color_image();
image.depth = cap.get_depth_image();
image.depth_in_color = transformation_.depth_image_to_color_camera(image.depth);
return image;
}
std::vector<Voxel> Camera::generate_point_cloud(Image &image) const {
k4a::image point_cloud = transformation_.depth_image_to_point_cloud(image.depth_in_color,
K4A_CALIBRATION_TYPE_COLOR);
int width = point_cloud.get_width_pixels();
int height = point_cloud.get_height_pixels();
long long num = width * height;
auto buff = (int16_t *) point_cloud.get_buffer();
auto color_points = (uint8_t *) image.color.get_buffer();
std::vector<Voxel> points(num);
for (int i = 0; i < num; i++) {
points[i].x = buff[i * 3];
points[i].y = buff[i * 3 + 1];
points[i].z = buff[i * 3 + 2];
points[i].b = color_points[i * 4];
points[i].g = color_points[i * 4 + 1];
points[i].r = color_points[i * 4 + 2];
}
return points;
}
void Camera::save_ply_file(const std::string& filename, const std::vector<Voxel>& points) {
// 打开文件
std::ofstream plyFile(filename);
if (!plyFile.is_open()) {
std::cerr << "无法打开文件 " << filename << std::endl;
return;
}
// 写入 PLY 文件头
plyFile << "ply\n";
plyFile << "format ascii 1.0\n";
plyFile << "element vertex " << points.size() << "\n";
plyFile << "property float x\n";
plyFile << "property float y\n";
plyFile << "property float z\n";
plyFile << "property uchar red\n";
plyFile << "property uchar green\n";
plyFile << "property uchar blue\n";
plyFile << "end_header\n";
// 写入点数据
for (const auto& point : points) {
plyFile << (float)point.x << " " << (float)point.y << " " << (float)point.z << " "
<< static_cast<int>(point.r) << " "
<< static_cast<int>(point.g) << " "
<< static_cast<int>(point.b) << "\n";
}
// 关闭文件
plyFile.close();
std::cout << "PLY file have saved in: " << filename << std::endl;
}
int main() {
Camera camera;
Image image = camera.get_image();
vector<Voxel> point_cloud = camera.generate_point_cloud(image);
Camera::save_ply_file("result.ply", point_cloud);
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。