C++中创建图像3D矩阵出现段错误,请求排查问题原因
你的段错误问题分析与修复方案
嘿,你的代码跑起来出现Segmentation fault主要是两个核心问题没搞对:OpenCV 3D矩阵的构造方式错误,以及元素访问的索引逻辑完全不符合多维矩阵的规则。让我一步步给你拆解清楚:
1. 3D Mat的构造参数完全写错了
你当前这段代码:
int Dark_size[3] = {row, col, cont}; // 暗场矩阵尺寸 Mat Dark_3D(cont, Dark_size, CV_16UC1); // 定义暗场矩阵
完全不符合OpenCV多维矩阵的构造规则。OpenCV里创建多维Mat的正确构造函数是这样的:
Mat(int ndims, const int* sizes, int type);
第一个参数是矩阵的维度数(你要的是3D,所以填3),而不是你写的cont(图像数量)。另外,建议把图像序号这个维度放在尺寸数组的第一位,这样后续访问时逻辑更顺,所以正确的构造代码应该是:
int Dark_size[3] = {cont, row, col}; // 维度顺序:图像数 → 行 → 列 Mat Dark_3D(3, Dark_size, CV_16UC1);
2. 3D矩阵的元素访问方式完全错误
你用Dark_3D.at<Vec3w>(i,j)[z]来赋值,这是典型的把3通道2D图像的访问方式套用到3D矩阵上了:
Vec3w是用来表示3通道2D图像中单个像素的3个通道值的类型,和3D半毛钱关系都没有;- 你定义的是
CV_16UC1(单通道16位无符号整数)的3D矩阵,每个元素就是单个ushort,所以得用at<ushort>配合正确的三维索引。
按照上面调整后的尺寸顺序,正确的赋值代码应该是:
Dark_3D.at<ushort>(z, i, j) = dark.at<ushort>(i,j);
如果非要坚持原来的{row, col, cont}尺寸顺序,那索引就得写成(i, j, z),但这样逻辑上不太直观,还是推荐把图像序号作为第一个维度。
修正后的完整代码
string folder = argv[1]; // 暗场文件夹 vector<String> fn; // 读取主文件夹下所有文件 glob(folder, fn, false); int cont = fn.size(); cvFits dark1(fn[0]); // 加载第一张图像以获取图像尺寸 int col = dark1.cols; int row = dark1.rows; // 修正:正确构造3D矩阵,调整维度顺序更符合逻辑 int Dark_size[3] = {cont, row, col}; Mat Dark_3D(3, Dark_size, CV_16UC1); // 修正:正确访问3D矩阵元素 for(int z = 0; z < cont; z++) { cvFits dark(fn[z]); for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { Dark_3D.at<ushort>(z, i, j) = dark.at<ushort>(i,j); } } }
额外的效率优化建议
如果你的图像数量很多,三重循环的速度会比较慢,你可以用memcpy来批量拷贝像素数据,比如把每张图像转成一维后直接拷贝到3D矩阵的对应切片(假设你的cvFits可以通过getMat()返回标准的OpenCV Mat对象):
for(int z = 0; z < cont; z++) { cvFits dark(fn[z]); Mat img_mat = dark.getMat(); // 假设这个方法能拿到图像的Mat Mat img_1d = img_mat.reshape(1, 1); // 把图像转成1行的一维矩阵 // 直接拷贝整个切片的数据 memcpy(Dark_3D.ptr<ushort>(z), img_1d.ptr<ushort>(), row * col * sizeof(ushort)); }
这样能大幅提升填充3D矩阵的速度,比逐像素循环快很多。
内容的提问来源于stack exchange,提问作者Tanozar
相关产品推荐
相关产品推荐

