多台Azure Kinect DK同步保存RGB和Depth图片

文章目录

  • 前言
  • 一、如何同步
  • 二、多摄像头同步
    • 1.官方代码如下:
    • 2.展示
  • 三、保存图片
    • 1.部分代码如下:
    • 2.展示
  • 参考

前言

最近有多台Azure Kinect DK摄像头同步保存RGB和Depth图片的需求,一开始我是直接调用编译好的recorder工具进行视频录制,然后从mkv视频中分别提取出RGB和Depth图片,发现提取出来的图片其实不太同步,看来光连接外部同步线还不够准确。于是就在网上找了一些博客看,还是没有太大的收获,最后发现在官方给的源码example中的green_screen找到了同步相关的代码,故进行了浅显地注释和学习。

一、如何同步

处理Azure Kinect DK摄像机还比较复杂:
(1)不能完全保证同一个摄像机中的深度相机和彩色相机拍摄图像的时间戳完全相等,或多个摄像机之间拍摄图像的时间戳完全相等
(2)如果两个最新的图像是同步的,那么还是不能保证在每个摄像机上只调用一次get_capture()后它们以后拍摄的图像仍然是同步的。

这是因为在摄像机内部,设备保留一个包含一些捕获图像的队列,并根据get_capture()的请求提供这些图像。然而,图像也可以随时丢弃,在给定时刻,一个设备可能比另一个设备准备更多的图像。此外,同步过程很复杂。当同步时,摄像机不能保证在所有时间戳上完全匹配(尽管它们应该非常接近)。所有延迟都与主摄像机的彩色摄像机有关。为了处理这些复杂性,在官方给出的同步代码中采用了一种相当简单的算法。从读取两个捕获开始,然后如果相机图像不是在大致相同的时间拍摄的,则从具有较旧捕获的设备读取一个新图像,直到时间戳大致匹配。每次循环运行时,只会更新旧的捕获,捕获存储在向量中,其中向量的第一个元素是主捕获,后续元素是从属捕获。

二、多摄像头同步

1.官方代码如下:

bool have_synced_images = false; //设置一个bool变量判断是否同步
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
while (!have_synced_images)
{
	// 如果这花费的时间太长,则超时
	int64_t duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
	if (duration_ms > WAIT_FOR_SYNCHRONIZED_CAPTURE_TIMEOUT)
	{
		cerr << "ERROR: Timedout waiting for synchronized captures\n";
		exit(1);
	}
	
	k4a::image master_color_image = captures[0].get_color_image(); //捕获到主设备的color_image
	
	std::chrono::microseconds master_color_image_time = master_color_image.get_device_timestamp(); //记录这个color_image的时间戳

	//开始处理从属设备
	for (size_t i = 0; i < subordinate_devices.size(); ++i)
	{   
		k4a::image sub_image;  // 要获取的捕获项
		if (compare_sub_depth_instead_of_color) //是否同步的是depth_image
		{
			sub_image = captures[i + 1].get_depth_image(); // 偏移1是因为captures[0]是master占用
		}
		else
		{
			sub_image = captures[i + 1].get_color_image(); 
		}

		
		if (master_color_image && sub_image) //这里主从设备的image都有了
		{
			std::chrono::microseconds sub_image_time = sub_image.get_device_timestamp();
			// 理想情况下,从属设备的彩色图像时间戳是主设备的彩色图像时间戳加上我们在主设备彩色摄像机和从属设备彩色摄像机之间配置的延迟
			std::chrono::microseconds expected_sub_image_time =
				master_color_image_time +
				std::chrono::microseconds{ sub_config.subordinate_delay_off_master_usec } +
				std::chrono::microseconds{ sub_config.depth_delay_off_color_usec };  //这里是把深度图像同步也给算进去了
			std::chrono::microseconds sub_image_time_error = sub_image_time - expected_sub_image_time;  //得到主从设备之间的误差时间
			
			// 从属相机时间戳滞后,从属相机重新捕获图片
			if (sub_image_time_error < -MAX_ALLOWABLE_TIME_OFFSET_ERROR_FOR_IMAGE_TIMESTAMP)
			{
				master_color_image.reset(); //释放
				sub_image.reset();
				log_lagging_time("sub", captures[0], captures[i + 1]);
				subordinate_devices[i].get_capture(&captures[i + 1], std::chrono::milliseconds{ K4A_WAIT_INFINITE });
				break; //跳出for循环
			}
			// 从属相机时间戳超前,主相机重新捕获图片
			else if (sub_image_time_error > MAX_ALLOWABLE_TIME_OFFSET_ERROR_FOR_IMAGE_TIMESTAMP)
			{
				master_color_image.reset();
				sub_image.reset();
				log_lagging_time("master", captures[0], captures[i + 1]);
				master_device.get_capture(&captures[0], std::chrono::milliseconds{ K4A_WAIT_INFINITE });
				break; //跳出for循环
			}
			// 误差在我们设定的范围之内,认定算同步了
			else
			{
				master_color_image.reset();
				sub_image.reset();
				if (i == subordinate_devices.size() - 1)  // 如果从属设备都同步了
				{
					log_synced_image_time(captures[0], captures[i + 1]);
					have_synced_images = true; // 可以跳出while循环了
				}
			}
		}
		//缺失主设备捕获的image
		else if (!master_color_image)
		{
			std::cout << "Master image was bad!\n";
			master_color_image.reset();
			captures[0].reset();
			master_device.get_capture(&captures[0], std::chrono::milliseconds{ K4A_WAIT_INFINITE });
			break;
		}
		//缺失从设备捕获的image
		else if (!sub_image)
		{   
			std::cout << "Subordinate image was bad!" << endl;
			sub_image.reset();
			captures[i+1].reset();
			subordinate_devices[i].get_capture(&captures[i + 1], std::chrono::milliseconds{ K4A_WAIT_INFINITE });
			break;
		}
	}
} //end while

2.展示

多台Azure Kinect DK同步保存RGB和Depth图片_第1张图片

三、保存图片

1.部分代码如下:

else if (num_divices == 2)
{   
	k4a::calibration secondary_calibration = capturer.get_subordinate_device_by_index(0).get_calibration(secondary_config.depth_mode,
																	secondary_config.color_resolution);
	k4a::transformation secondary_depth_to_secondary_color(secondary_calibration);

	int pictureNums = 0;
	while (1)
	{
		vector<k4a::capture> captures;
		captures = capturer.get_synchronized_captures(secondary_config, true);
		k4a::image main_color_image = captures[0].get_color_image();
		k4a::image main_depth_image = captures[0].get_depth_image();
		//记录时间戳
		int64_t main_color_image_time = main_color_image.get_device_timestamp().count();
		int64_t main_depth_image_time = main_depth_image.get_device_timestamp().count();
		// 将主设备深度图像放入彩色摄像机空间
		k4a::image main_depth_in_main_color = create_depth_image_like(main_color_image);
		main_depth_to_main_color.depth_image_to_color_camera(main_depth_image, &main_depth_in_main_color);
		cv::Mat cv_main_depth_in_main_color = depth_to_opencv(main_depth_in_main_color); //获取到的主设备的depth图
		cv::Mat cv_main_color_image = color_to_opencv(main_color_image); //获取到的主设备的rgb图
		

		k4a::image secondary_color_image = captures[1].get_color_image();
		k4a::image secondary_depth_image = captures[1].get_depth_image();
		int64_t secondary_color_image_time = secondary_color_image.get_device_timestamp().count();
		int64_t secondary_depth_image_time = secondary_depth_image.get_device_timestamp().count();

		// 将子设备深度图像放入彩色摄像机空间
		k4a::image secondary_depth_in_main_color = create_depth_image_like(main_color_image);
		secondary_depth_to_secondary_color.depth_image_to_color_camera(secondary_depth_image,
																  &secondary_depth_in_main_color);
		cv::Mat cv_secondary_depth_in_main_color = depth_to_opencv(secondary_depth_in_main_color);
		cv::Mat cv_secndary_color_image = color_to_opencv(secondary_color_image);

		//保存
		std::string filename_main_rgb = std::to_string(main_color_image_time)+".png";
		std::string filename_main_depth = std::to_string(main_depth_image_time)+".png";
		std::string filename_secondary_rgb = std::to_string(secondary_color_image_time)+".png";
		std::string filename_secondary_depth = std::to_string(secondary_depth_image_time)+".png";

		cout<<"************* saving pictures ***********"<<endl;
		imwrite("./depth_master/"+filename_main_rgb, cv_main_depth_in_main_color);
		imwrite("./rgb_master/"+filename_main_depth, cv_main_color_image);
		imwrite("./depth_sub/"+filename_secondary_rgb, cv_secondary_depth_in_main_color);
		imwrite("./rgb_sub/"+filename_secondary_depth, cv_secndary_color_image);

		if(pictureNums != 30){
			++pictureNums;
			continue;
		}else{
			break;
		}
	}
}

2.展示

这里就直接放上移到我U盘里的截图
多台Azure Kinect DK同步保存RGB和Depth图片_第2张图片

参考

1.https://github.com/microsoft/Azure-Kinect-Sensor-SDK/tree/develop/examples/green_screen

你可能感兴趣的:(Azure,Kinect,DK,azure,人工智能,microsoft,ubuntu)