但是任何人都可以向我解释一下,或者给我一些有关它们如何计算的参考吗? Canny的边缘检测器谈论的是5x5高斯滤波器,但是他们如何获得这些特定的数字呢?以及它们如何从连续卷积变为矩阵乘法?
#1 楼
为了使此操作有效,您需要想象图像被重新成形为矢量。然后,此矢量在其左侧乘以卷积矩阵以获得模糊图像。
请注意,结果也是一个与输入大小相同的向量,即一个大小相同的图像。
卷积矩阵的每一行对应于输入图像中的一个像素。
包含图像中所有其他像素对所考虑像素的模糊对应部分的贡献权重。
让我们举个例子:图像大小为$ 3的框模糊乘以3 $像素大小$ 6 \ times 6 $像素。
重塑后的图像是一列36个选举元素,而模糊矩阵的大小为$ 36 \ times 36 $。到处都是0。
现在,考虑输入图像中坐标$(i,j)$的像素(为简单起见,不在其边界上)。通过对自身及其在位置$(i-1,j-1)的每个邻居施加$ 1/9 $的权重,可以获得模糊的对应物。 (i-1,j),(i-1,j + 1),\ ldots,(i + 1,j + 1)$。
在列向量中,像素$(i,j)$的位置为$ 6 * i + j $(假设字典顺序)。我们在模糊矩阵的第((6i + j)$)行中报告了权重$ 1/9 $。
对所有其他像素执行相同操作。
密切相关的过程(卷积+减法)可以在此博客文章中找到(来自我的个人博客)。
评论
$ \ begingroup $
链接无效。
$ \ endgroup $
–高特
2015年9月4日在11:31
#2 楼
为了应用于图像或卷积网络,为了更有效地使用现代GPU中的矩阵乘法器,通常将输入重新整形为激活矩阵的列,然后可以将这些矩阵与多个过滤器/内核立即相乘。从Stanford的CS231n中查看此链接,然后向下滚动至“以矩阵乘法实现”部分以获取详细信息。输入图像或激活图,将其与内核相乘,然后通过通常称为im2col的操作将其拉伸为新矩阵X的列。内核也被拉伸以填充权重矩阵W的行,以便在执行矩阵运算W * X时,所得矩阵Y具有所有卷积结果。最后,必须通过通常称为cal2im的操作将列转换回图像,从而重新调整Y矩阵的形状。
评论
$ \ begingroup $
这是一个很好的链接,谢谢!但是,优良作法是将链接中的重要摘录添加到答案中,这样即使链接断开,答案仍然有效。请考虑编辑您的答案以使其被接受!
$ \ endgroup $
–马特奥
17-2-23在18:27
#3 楼
时域中的卷积等于频域中的矩阵乘法,反之亦然。滤波等效于时域中的卷积,因此等效于频域中的矩阵乘法。
对于5x5的地图或蒙版,它们来自离散化canny / sobel运算符。
评论
$ \ begingroup $
我不同意过滤是频域中的卷积这一事实。我们在这里讨论的滤波器类型是空间域中的卷积(也就是说,通过频域中的滤波器响应进行逐元素乘法)。
$ \ endgroup $
–小食
13年3月16日在16:51
$ \ begingroup $
感谢您纠正我写的内容。我进行了后续编辑。我想我应该在发布之前仔细检查我的答案。但是,我的大部分回答仍然有效。
$ \ endgroup $
–那雷什
13年3月17日在4:15
$ \ begingroup $
傅立叶变换确实将卷积变成乘法(反之亦然)。但是,它们是品脱乘法,而问题是关于通过重塑图像获得的矩阵矢量乘法。
$ \ endgroup $
–sansuiso
13年3月17日在16:34
$ \ begingroup $
我确实提到了运算符离散的原因是canny / sobel运算符获得5x5矩阵的原因。
$ \ endgroup $
–那雷什
13年3月17日在17:49
#4 楼
我在StackOverflow Q2080835 GitHub Repository(请参阅CreateImageConvMtx()
)中编写了一个可以解决此问题的函数。 />代码如下:function [ mK ] = CreateImageConvMtx( mH, numRows, numCols, convShape )
CONVOLUTION_SHAPE_FULL = 1;
CONVOLUTION_SHAPE_SAME = 2;
CONVOLUTION_SHAPE_VALID = 3;
switch(convShape)
case(CONVOLUTION_SHAPE_FULL)
% Code for the 'full' case
convShapeString = 'full';
case(CONVOLUTION_SHAPE_SAME)
% Code for the 'same' case
convShapeString = 'same';
case(CONVOLUTION_SHAPE_VALID)
% Code for the 'valid' case
convShapeString = 'valid';
end
mImpulse = zeros(numRows, numCols);
for ii = numel(mImpulse):-1:1
mImpulse(ii) = 1; %<! Create impulse image corresponding to i-th output matrix column
mTmp = sparse(conv2(mImpulse, mH, convShapeString)); %<! The impulse response
cColumn{ii} = mTmp(:);
mImpulse(ii) = 0;
end
mK = cell2mat(cColumn);
end
我还创建了一个函数来创建图像过滤矩阵(类似于MATLAB的
full
):function [ mK ] = CreateImageFilterMtx( mH, numRows, numCols, operationMode, boundaryMode )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
OPERATION_MODE_CONVOLUTION = 1;
OPERATION_MODE_CORRELATION = 2;
BOUNDARY_MODE_ZEROS = 1;
BOUNDARY_MODE_SYMMETRIC = 2;
BOUNDARY_MODE_REPLICATE = 3;
BOUNDARY_MODE_CIRCULAR = 4;
switch(operationMode)
case(OPERATION_MODE_CONVOLUTION)
mH = mH(end:-1:1, end:-1:1);
case(OPERATION_MODE_CORRELATION)
% mH = mH; %<! Default Code is correlation
end
switch(boundaryMode)
case(BOUNDARY_MODE_ZEROS)
mK = CreateConvMtxZeros(mH, numRows, numCols);
case(BOUNDARY_MODE_SYMMETRIC)
mK = CreateConvMtxSymmetric(mH, numRows, numCols);
case(BOUNDARY_MODE_REPLICATE)
mK = CreateConvMtxReplicate(mH, numRows, numCols);
case(BOUNDARY_MODE_CIRCULAR)
mK = CreateConvMtxCircular(mH, numRows, numCols);
end
end
function [ mK ] = CreateConvMtxZeros( mH, numRows, numCols )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
numElementsImage = numRows * numCols;
numRowsKernel = size(mH, 1);
numColsKernel = size(mH, 2);
numElementsKernel = numRowsKernel * numColsKernel;
vRows = reshape(repmat(1:numElementsImage, numElementsKernel, 1), numElementsImage * numElementsKernel, 1);
vCols = zeros(numElementsImage * numElementsKernel, 1);
vVals = zeros(numElementsImage * numElementsKernel, 1);
kernelRadiusV = floor(numRowsKernel / 2);
kernelRadiusH = floor(numColsKernel / 2);
pxIdx = 0;
elmntIdx = 0;
for jj = 1:numCols
for ii = 1:numRows
pxIdx = pxIdx + 1;
for ll = -kernelRadiusH:kernelRadiusH
for kk = -kernelRadiusV:kernelRadiusV
elmntIdx = elmntIdx + 1;
pxShift = (ll * numCols) + kk;
if((ii + kk <= numRows) && (ii + kk >= 1) && (jj + ll <= numCols) && (jj + ll >= 1))
vCols(elmntIdx) = pxIdx + pxShift;
vVals(elmntIdx) = mH(kk + kernelRadiusV + 1, ll + kernelRadiusH + 1);
else
vCols(elmntIdx) = pxIdx;
vVals(elmntIdx) = 0; % See the accumulation property of 'sparse()'.
end
end
end
end
end
mK = sparse(vRows, vCols, vVals, numElementsImage, numElementsImage);
end
function [ mK ] = CreateConvMtxSymmetric( mH, numRows, numCols )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
numElementsImage = numRows * numCols;
numRowsKernel = size(mH, 1);
numColsKernel = size(mH, 2);
numElementsKernel = numRowsKernel * numColsKernel;
vRows = reshape(repmat(1:numElementsImage, numElementsKernel, 1), numElementsImage * numElementsKernel, 1);
vCols = zeros(numElementsImage * numElementsKernel, 1);
vVals = zeros(numElementsImage * numElementsKernel, 1);
kernelRadiusV = floor(numRowsKernel / 2);
kernelRadiusH = floor(numColsKernel / 2);
pxIdx = 0;
elmntIdx = 0;
for jj = 1:numCols
for ii = 1:numRows
pxIdx = pxIdx + 1;
for ll = -kernelRadiusH:kernelRadiusH
for kk = -kernelRadiusV:kernelRadiusV
elmntIdx = elmntIdx + 1;
pxShift = (ll * numCols) + kk;
if(ii + kk > numRows)
pxShift = pxShift - (2 * (ii + kk - numRows) - 1);
end
if(ii + kk < 1)
pxShift = pxShift + (2 * (1 -(ii + kk)) - 1);
end
if(jj + ll > numCols)
pxShift = pxShift - ((2 * (jj + ll - numCols) - 1) * numCols);
end
if(jj + ll < 1)
pxShift = pxShift + ((2 * (1 - (jj + ll)) - 1) * numCols);
end
vCols(elmntIdx) = pxIdx + pxShift;
vVals(elmntIdx) = mH(kk + kernelRadiusV + 1, ll + kernelRadiusH + 1);
end
end
end
end
mK = sparse(vRows, vCols, vVals, numElementsImage, numElementsImage);
end
function [ mK ] = CreateConvMtxReplicate( mH, numRows, numCols )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
numElementsImage = numRows * numCols;
numRowsKernel = size(mH, 1);
numColsKernel = size(mH, 2);
numElementsKernel = numRowsKernel * numColsKernel;
vRows = reshape(repmat(1:numElementsImage, numElementsKernel, 1), numElementsImage * numElementsKernel, 1);
vCols = zeros(numElementsImage * numElementsKernel, 1);
vVals = zeros(numElementsImage * numElementsKernel, 1);
kernelRadiusV = floor(numRowsKernel / 2);
kernelRadiusH = floor(numColsKernel / 2);
pxIdx = 0;
elmntIdx = 0;
for jj = 1:numCols
for ii = 1:numRows
pxIdx = pxIdx + 1;
for ll = -kernelRadiusH:kernelRadiusH
for kk = -kernelRadiusV:kernelRadiusV
elmntIdx = elmntIdx + 1;
pxShift = (ll * numCols) + kk;
if(ii + kk > numRows)
pxShift = pxShift - (ii + kk - numRows);
end
if(ii + kk < 1)
pxShift = pxShift + (1 -(ii + kk));
end
if(jj + ll > numCols)
pxShift = pxShift - ((jj + ll - numCols) * numCols);
end
if(jj + ll < 1)
pxShift = pxShift + ((1 - (jj + ll)) * numCols);
end
vCols(elmntIdx) = pxIdx + pxShift;
vVals(elmntIdx) = mH(kk + kernelRadiusV + 1, ll + kernelRadiusH + 1);
end
end
end
end
mK = sparse(vRows, vCols, vVals, numElementsImage, numElementsImage);
end
function [ mK ] = CreateConvMtxCircular( mH, numRows, numCols )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
numElementsImage = numRows * numCols;
numRowsKernel = size(mH, 1);
numColsKernel = size(mH, 2);
numElementsKernel = numRowsKernel * numColsKernel;
vRows = reshape(repmat(1:numElementsImage, numElementsKernel, 1), numElementsImage * numElementsKernel, 1);
vCols = zeros(numElementsImage * numElementsKernel, 1);
vVals = zeros(numElementsImage * numElementsKernel, 1);
kernelRadiusV = floor(numRowsKernel / 2);
kernelRadiusH = floor(numColsKernel / 2);
pxIdx = 0;
elmntIdx = 0;
for jj = 1:numCols
for ii = 1:numRows
pxIdx = pxIdx + 1;
for ll = -kernelRadiusH:kernelRadiusH
for kk = -kernelRadiusV:kernelRadiusV
elmntIdx = elmntIdx + 1;
pxShift = (ll * numCols) + kk;
if(ii + kk > numRows)
pxShift = pxShift - numRows;
end
if(ii + kk < 1)
pxShift = pxShift + numRows;
end
if(jj + ll > numCols)
pxShift = pxShift - (numCols * numCols);
end
if(jj + ll < 1)
pxShift = pxShift + (numCols * numCols);
end
vCols(elmntIdx) = pxIdx + pxShift;
vVals(elmntIdx) = mH(kk + kernelRadiusV + 1, ll + kernelRadiusH + 1);
end
end
end
end
mK = sparse(vRows, vCols, vVals, numElementsImage, numElementsImage);
end
代码已针对MATLAB
same
进行了验证。完整的代码可在我的网站上找到。 StackOverflow Q2080835 GitHub存储库。
评论
dsp.stackexchange.com/questions/2969/…我添加了带有完整代码的答案,用于生成图像卷积矩阵。
请参阅如何将卷积运算实现为矩阵向量乘法?。