我想自己用C ++实现2D卷积函数,而不使用filter2D()。我试图迭代输入图像和内核的所有像素,然后将新值分配给dst的每个像素。但是,我收到此错误。
线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x0)
我发现此错误表明我正在访问nullptr,但无法解决问题。这是我的c ++代码。
cv::Mat_<float> spatialConvolution(const cv::Mat_<float>& src, const cv::Mat_<float>& kernel)
{
// declare variables
Mat_<float> dst;
Mat_<float> flipped_kernel;
float tmp = 0.0;
// flip kernel
flip(kernel, flipped_kernel, -1);
// multiply and integrate
// input rows
for(int i=0;i<src.rows;i++){
// input columns
for(int j=0;j<src.cols;j++){
// kernel rows
for(int k=0;k<flipped_kernel.rows;k++){
// kernel columns
for(int l=0;l<flipped_kernel.cols;l++){
tmp += src.at<float>(i,j) * flipped_kernel.at<float>(k,l);
}
}
dst.at<float>(i,j) = tmp;
}
}
return dst.clone();
}
您的内存访问错误可能是由于以下原因引起的:
dst.at<float>(i,j) = tmp;
因为dst
未初始化。如果矩阵的索引没有大小/数据,则无法为其分配某些内容。相反,请首先初始化矩阵,因为Mat_<float>
是声明,而不是初始化。使用可以在其中指定cv::Size
或从Mat
的不同构造函数指定行/列的初始化之一(请参见the docs)。例如,您可以使用以下方法初始化dst
:
Mat dst{src.size(), src.type()};
为简单起见,假设您拥有3x3内核
k(0,0) k(0,1) k(0,2)
k(1,0) k(1,1) k(1,2)
k(2,0) k(2,1) k(2,2)
要计算卷积,您要从左到右,从上到下扫描输入图像(标记为I
)并为输入图像的每个像素分配一个根据以下公式计算得出的值:
newValue(y,x) = I(y-1,x-1) * k(0,0) + I(y-1,x) * k(0,1) + I(y-1,x+1) * k(0,2)
+ I(y,x-1) * k(1,0) + I(y,x) * k(1,1) + I(y,x+1) * k(1,2) +
+ I(y+1,x-1) * k(2,0) + I(y+1,x) * k(2,1) + I(y+1,x+1) * k(2,2)
------------------x------------>
|
|
| [k(0,0) k(0,1) k(0,2)]
y [k(1,0) k(1,1) k(1,2)]
| [k(2,0) k(2,1) k(2,2)]
|
输入图像((y,x)
)的[I
是内核的锚点,为I(y,x)
分配新值您需要将每个k
系数乘以I
的对应点-您的代码不执行此操作。
首先,您需要创建具有原始图像尺寸和相同像素类型的dst
矩阵。然后,您需要重写循环以反映上述公式:
cv::Mat_<float> spatialConvolution(const cv::Mat_<float>& src, const cv::Mat_<float>& kernel)
{
Mat dst(src.rows,src.cols,src.type());
Mat_<float> flipped_kernel;
flip(kernel, flipped_kernel, -1);
const int dx = kernel.cols / 2;
const int dy = kernel.rows / 2;
for (int i = 0; i<src.rows; i++)
{
for (int j = 0; j<src.cols; j++)
{
float tmp = 0.0f;
for (int k = 0; k<flipped_kernel.rows; k++)
{
for (int l = 0; l<flipped_kernel.cols; l++)
{
int x = j - dx + l;
int y = i - dy + k;
if (x >= 0 && x < src.cols && y >= 0 && y < src.rows)
tmp += src.at<float>(y, x) * flipped_kernel.at<float>(k, l);
}
}
dst.at<float>(i, j) = saturate_cast<float>(tmp);
}
}
return dst.clone();
}