如何在Matlab中得到一个用复制表示2d卷积的二维卷积矩阵。所以我想要的是这样的东西:
T = getConvMtx(H, m, n);
res1 = T * im;
res2 = imfilter(im, H, 'replicate');并使res1和res2有效相等。
Matlab的convmtx2实现给出了一个假定零填充的卷积矩阵。
我已经将我的实现作为答案之一,尽管它效率极低。这就是为什么我会重视、反馈和建议一个更好的方法。
发布于 2014-10-01 21:49:38
以下是我如何设法获得所需的结果。然而,它效率很低,因此任何反馈意见和建议都是非常欢迎的:
function T = getConvMtx(H,m,n)
vHalfKerSz = floor(size(H) / 2);
mInds = reshape(1:m*n, m, n);
mInds = padarray(mInds, vHalfKerSz, 'replicate');
Tcols = zeros(m*n*numel(H), 1);
Trows = zeros(m*n*numel(H), 1);
Tvals = zeros(m*n*numel(H), 1);
i = 0; p = 0;
for c = 1:n
    for r = 1:m
        p = p + 1;
        mKerInds = mInds(r:r+size(H,1)-1, c:c+size(H,2)-1);
        [U, ~, ic] = unique(mKerInds(:));
        for k = 1:length(U)
            i = i + 1;
            Tcols(i) = U(k);
            Trows(i) = p;
            Tvals(i) = sum(H(mKerInds == U(k)));
        end
    end
end
T = sparse(Trows(1:i), Tcols(1:i), Tvals(1:i), m*n, m*n);
end以及一些示例用法:
n = 100;
im = rand(n);
h = fspecial('gaussian', 5, 1);
mConvMtx = getConvMtx(h, n, n);
im2 = reshape(mConvMtx * im(:), size(im));
im3 = imfilter(im, h, 'replicate');
% figure;imshow(im3);
% figure;imshow(im2);
sum(abs(im2(:) - im3(:)))  %will give a very small number due to precision issues以下是按顺序排列的结果(im、im2、im3):



发布于 2019-01-15 19:23:20
我创建了一个函数来创建用于图像过滤的矩阵(类似于MATLAB的imfilter()):
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 imfilter()对该程序进行了验证。
它不是经过优化的(不是以矢量化的方式编写的),因为我编写它是为了让人们能够轻松地掌握正在发生的事情。
完整的代码可以在我的StackOverflow Q2080835 GitHub库房中获得。
https://stackoverflow.com/questions/26151265
复制相似问题