Bir Konvolüsyon Matris Çarpımı (Matris Formu) Olarak Nasıl İfade Edilebilir?


11

Bu sorunun programlama ile çok ilgili olmayabileceğini biliyorum, ancak görüntü işlemenin arkasındaki teoriyi anlamazsam, pratikte hiçbir zaman bir şey uygulayamayacağım.

Doğru anladıysam Gauss filtreleri, bir pikselin mahallesinin ağırlıklı bir ortalamasını hesapladıkları ve aynı zamanda bir bulanıklık uygulayabildiğiniz ve görüntüyü aynı anda türetebileceğiniz için gürültü azaltma için bir görüntü ile kıvrılır. sadece bir Gauss fonksiyonunun türevi ile kıvrılıyor.

Ama kimse bana açıklayabilir veya nasıl hesaplandıklarına dair bazı referanslar verebilir mi?

Örneğin, Canny'nin kenar dedektörü 5x5 Gauss filtresinden bahsediyor, ancak bu belirli sayıları nasıl elde ettiler? Ve sürekli bir evrişimden bir Matrix çarpımına nasıl geçtiler?



Ben bir cevap ekledi Görüntü konvülasyon için bir matris oluşturmak için tam koduyla.
Royi

Yanıtlar:


3

Bu işlemin çalışması için, görüntünüzün bir vektör olarak yeniden şekillendirildiğini düşünmeniz gerekir. Daha sonra, bu vektör bulanık görüntüyü elde etmek için solda evrişim matrisi ile çarpılır. Sonucun aynı zamanda girdi ile aynı boyutta bir vektör, yani aynı boyutta bir görüntü olduğuna dikkat edin.

Katlamalı matrisin her satırı giriş görüntüsündeki bir piksele karşılık gelir. Görüntüdeki diğer tüm piksellerin, dikkate alınan pikselin bulanık karşılığına katkılarının ağırlığını içerir.

Bir örnek verelim: kutu boyutunda bulanıklık 3×3 boyuttaki bir resimdeki pikseller 6×6piksel. Yeniden şekillendirilen görüntü 36 seçim sütunu, bulanıklaştırma matrisinin boyutu ise36×36.

  • Bu matrisi her yerde 0'a başlatalım.
  • Şimdi, koordinatların pikselini düşünün (i,j)giriş görüntüsünde (basitlik için sınırında değil). Bulanık muadili bir ağırlık uygulanarak elde edilir.1/9 görevlerine ve komşularının her birine (i1,j1);(i1,j),(i1,j+1),,(i+1,j+1).
  • Sütun vektöründe piksel (i,j) pozisyonu var 6i+j(sözlükbilimsel sıralama varsayarak). ağırlığı rapor ediyoruz1/9 içinde (6i+j)matrisinin ikinci satırı.
  • Aynısını diğer tüm piksellerle yapın.

Bu blog gönderisinde (kişisel blogumdan) yakından ilişkili bir sürecin (evrişim + çıkarma) görsel bir resmini bulabilirsiniz .


bir bağlantı öldü.
gauteh

2

Görüntülere veya evrişim ağlarına yönelik uygulamalarda, modern GPU'larda matris çarpanlarını daha verimli kullanmak için, girişler tipik olarak bir aktivasyon matrisinin sütunlarına yeniden şekillendirilir ve bunlar bir kerede birden fazla filtre / çekirdek ile çarpılabilir.

Check out bu bağlantıyı Stanford CS231n gelen ve ayrıntılar için "Matrix Çarpma olarak Uygulanması" konulu bölümüne gidin.

İşlem, bir giriş görüntüsü veya aktivasyon haritası üzerindeki tüm yerel yamaları, çekirdekle çarpılacak olanları ve genellikle im2col adı verilen bir işlemle yeni bir X matrisinin sütununa uzatarak çalışır. Çekirdekler ayrıca bir ağırlık matrisinin W sıralarını doldurmak için gerilir, böylece W * X matris işlemini gerçekleştirirken, elde edilen Y matrisi evrişimin tüm sonuçlarına sahiptir. Son olarak, Y matrisi, tipik olarak cal2im adı verilen bir işlemle sütunları tekrar resimlere dönüştürerek yeniden şekillendirilmelidir.


1
Bu çok iyi bir link, teşekkürler! Bununla birlikte, bağlantıdan önemli alıntıları cevaba eklemek iyi bir uygulamadır, bu nedenle bağlantı kopsa bile cevap geçerlidir. Lütfen yanıtınızı kabul etmek için düzenlemeyi düşünün!
Matteo

1

Zaman alanındaki konvolüsyon, frekans alanındaki matris çarpımına eşittir veya bunun tersi de geçerlidir.

Filtreleme, zaman alanındaki konvolüsyona ve dolayısıyla frekans alanındaki matris çarpımına eşdeğerdir.

5x5 haritalarına veya maskelerine gelince, canny / sobel operatörlerini takdir etmekten geliyorlar.


2
Filtrelemenin frekans alanında bir evrişim olduğu gerçeğine katılmıyorum. Burada bahsettiğimiz filtreler, uzaysal alandaki kıvrımlardır (yani, frekans alanındaki filtre tepkisi ile eleman bazında çarpma).
Mart'ta

Yazdıklarımı düzelttiğiniz için teşekkürler. Sonradan bir düzenleme yaptım. Göndermeden önce cevaplarımı tekrar kontrol etmeliyim sanırım. Ancak cevabımın çoğunluğu hala geçerli.
Naresh

Fourier dönüşümü gerçekten kıvrımları çarpmalara (veya tersi) dönüştürür. Bununla birlikte, bunlar pint-çarpımlarıdır, soru ise görüntüleri yeniden şekillendirerek elde edilen matris-vektör çarpımlarıdır.
sansuiso

Canny / sobel operatörleri için elde edilen 5x5 matrislerin nedeninin operatörlerin ayrıklaştırılmasından bahsetmiştim.
Naresh

1

Bunu StackOverflow Q2080835 GitHub Deposunda (Bir göz atın CreateImageConvMtx()) çözen bir işlev yazdım .
Aslında fonksiyon istediğiniz herhangi bir evrişim şeklini destekleyebilir - full, sameve valid.

Kod aşağıdaki gibidir:

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

Ayrıca Görüntü Filtreleme için bir Matris (MATLAB en benzer fikirler imfilter()) oluşturmak için bir işlev oluşturdu :

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

Kod MATLAB'a göre doğrulandı imfilter().

Tam kodu StackOverflow Q2080835 GitHub Depomda bulabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.