0

我已经为 Rust 中的相机库编写了一个包装器,它命令和操作相机,还使用 ​​bindgen 将图像保存到文件中。一旦我命令开始曝光(基本上是告诉相机拍摄图像),我可以使用以下形式的函数抓取图像:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u8],) -> u32 //(u32 is a retval)

在 C++ 中,这个函数是:

uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)

在 C++ 中,我可以传入表单的缓冲区,imgdata = new unsigned char[length_buffer]该函数将使用来自相机的图像数据填充缓冲区。

在 Rust 中,类似地,我可以传入 Vec: 形式的缓冲区let mut buffer: Vec<u8> = Vec::with_capacity(length_buffer)

目前,我构建代码的方式是有一个主结构,其中包含图像的宽度和高度、相机句柄等设置,包括图像缓冲区。该结构已被初始化为mut

let mut main_settings = MainSettings {
width: 9600,
...,
buffer: Vec::with_capacity(length_buffer),
}

我编写了一个单独的函数,它将主结构作为参数并调用 GetQHYCCDSingleFrame 函数:

fn grab_image(main_settings: &mut MainSettings) {
let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };
}

调用此函数后,如果我立即检查 main_settings.image_buffer 的长度和容量:

println!("Elements in buffer are {}, capacity of buffer is {}.", main_settings.image_buffer.len(), main_settings.image_buffer.capacity());

我得到 0 作为长度,buffer_length 作为容量。类似地,打印任何索引,例如main_settings.image_buffer[0]or 1 会导致恐慌退出说len is 0.

这会让我认为GetQHYCCDSingleFrame代码无法正常工作,但是,当我使用fitsioand hdu.write_region(fitsio docs linked here)将 image_buffer 保存到文件时,我使用:

let ranges = [&(x_start..(x_start + roi_width)), &(y_start..(y_start+roi_height))];
hdu.write_region(&mut fits_file, &ranges, &main_settings.image_buffer).expect("Could not write to fits file");

这会将实际图像保存到具有正确大小的文件中,并且是一个非常精细的图像(如果我使用 C++ 程序拍摄时的样子)。但是,当我尝试打印缓冲区时,由于某种原因是空的,但hdu.write_region代码能够以某种方式访问​​数据。

目前,我的(不好的)解决方法是创建另一个向量,从保存的文件中读取数据并保存到缓冲区,然后该缓冲区具有正确数量的元素:

main_settings.new_buffer = hdu.read_region(&mut fits_file, &ranges).expect("Couldn't read fits file");  

hdu.write_region当函数可以从某个地方访问数据时,为什么我根本无法访问原始缓冲区,为什么它报告长度为 0 ?它究竟从哪里访问数据,我如何才能正确访问它?我对借用和引用有点陌生,所以我相信我在借用/引用缓冲区时可能做错了什么,还是别的什么?

对不起,长篇大论,但细节可能对这里的一切都很重要。谢谢!

4

1 回答 1

2

好吧,首先,您需要知道这一点,Vec<u8>并且&mut [u8]与 C 或 C++ 的uint8_t *. 主要区别在于,Vec<u8>数组&mut [u8]或切片的大小保存在它们内部,而uint8_t *没有。Rust 等价于 C/C++ 指针是原始指针,例如*mut [u8]. 原始指针可以安全构建,但需要unsafe使用。但是,即使它们是不同的类型,智能指针&mut [u8]也可以转换为原始指针而不会发出 AFAIK 问题。

其次,a 的容量Vec与其大小不同。实际上,为了获得良好的性能,aVec分配的内存比您使用的多,以避免在添加到向量中的每个新元素上重新分配。然而,长度是使用部分的大小。在您的情况下,您要求Vec分配一个长度为的堆空间length_buffer,但您没有告诉他们考虑要使用的任何已分配空间,因此初始长度为 0。由于 C++ 不知道Vec并且仅使用一个原始指针,它不能改变写在里面的长度Vec,它保持在0。因此恐慌。

为了解决它,我看到了多种解决方案:

  • 更改Vec::with_capacity(length_buffer)into vec![0; length_buffer],明确要求length_buffer从一开始就有一个长度

  • 使用unsafe代码显式设置的长度Vec而不触及里面的内容(使用Vec::from_raw_parts)。这可能比第一个解决方案更快,但我不确定。

  • 使用 a Box<[u8; length_buffer]>,类似于 aVec但没有重新分配,长度为容量

  • 如果您length_buffer在编译时保持不变,则使用 a[u8; length_buffer]会更有效,因为不需要分配,但它有缺点,您可能知道

于 2021-10-22T18:37:03.450 回答