自行实现C++ 2D卷积函数触发EXC_BAD_ACCESS错误求助
解决你的2D卷积实现崩溃问题
嘿,我来帮你搞定这个崩溃和逻辑错误!你遇到的Thread 1: EXC_BAD_ACCESS本质是未初始化的空矩阵访问,再加上卷积计算逻辑完全不对,咱们一步步修正:
核心问题分析
1. 目标图像dst未初始化
你只声明了Mat_<float> dst;但没给它分配内存,此时dst是空矩阵,直接用dst.at<float>(i,j)赋值必然触发空指针错误——这就是你崩溃的直接原因。
2. 卷积计算逻辑错误
你现在的代码是把输入图像的同一个像素src(i,j)和整个核的所有元素相乘累加,这完全不是卷积的逻辑!卷积需要让核的每个元素对应输入图像的对应位置像素,还要考虑核的中心对齐。
3. 临时变量tmp未重置
你只在开头初始化了一次tmp=0.0,后续计算每个像素时tmp会一直累加之前的结果,导致数值完全错误。
修正后的完整代码
cv::Mat_<float> spatialConvolution(const cv::Mat_<float>& src, const cv::Mat_<float>& kernel) { // 先做输入合法性校验,避免空矩阵导致后续错误 if (src.empty() || kernel.empty()) { return cv::Mat_<float>(); } // 获取核的尺寸与中心偏移量 int kernel_rows = kernel.rows; int kernel_cols = kernel.cols; int kernel_half_row = kernel_rows / 2; int kernel_half_col = kernel_cols / 2; // 初始化目标图像:和输入同尺寸、同类型,避免空指针 cv::Mat_<float> dst(src.size(), src.type()); cv::Mat_<float> flipped_kernel; // 翻转核(卷积操作需要先翻转核,等价于数学上的卷积定义) cv::flip(kernel, flipped_kernel, -1); // 遍历目标图像的每个像素 for(int i = 0; i < src.rows; i++){ for(int j = 0; j < src.cols; j++){ float tmp = 0.0; // 每个像素计算前重置临时变量 // 遍历核的每个元素 for(int k = 0; k < kernel_rows; k++){ for(int l = 0; l < kernel_cols; l++){ // 计算输入图像中对应核元素的坐标 int src_row = i - kernel_half_row + k; int src_col = j - kernel_half_col + l; // 边界检查:只有坐标在输入图像范围内时才计算 if (src_row >= 0 && src_row < src.rows && src_col >= 0 && src_col < src.cols) { tmp += src.at<float>(src_row, src_col) * flipped_kernel.at<float>(k, l); } // 边界外的区域默认按0处理,也可以改成复制边缘等方式 } } // 赋值给目标图像的对应像素 dst.at<float>(i, j) = tmp; } } return dst; // 无需clone,直接返回即可 }
关键修改说明
- 初始化
dst:直接用dst(src.size(), src.type())创建和输入同尺寸、同类型的矩阵,彻底解决空指针问题。 - 边界检查:避免访问输入图像的越界位置,这也是潜在的崩溃点。
- 重置
tmp:在每个目标像素计算前重置临时变量,保证结果正确。 - 修正卷积索引:让核的每个元素对应输入图像的对应位置,真正实现卷积计算。
- 输入校验:提前过滤空矩阵输入,避免后续逻辑出错。
如果你想优化边缘效果(比如避免边缘出现黑边),可以把边界外的处理改成复制边缘像素,比如当src_row <0时用src_row=0,src_row >=src.rows时用src_row=src.rows-1即可。
内容的提问来源于stack exchange,提问作者Marlowe
相关产品推荐
相关产品推荐

