简体   繁体   中英

Implementation of 2D Convolution in C

This is the function I have written for 2D Convolution in C:

typedef struct PGMImage{
    int w;
    int h;
    int* data;
}GrayImage;

GrayImage Convolution2D(GrayImage image,GrayImage kernel){
    int aH,aW,bW,bH,r,c,x,y,xx,yy,X,Y;
    int temp = 0;
    GrayImage conv;
    CreateGrayImage(&conv,image.w,image.h);
    aH = image.h;
    aW = image.w;
    bH = kernel.h;
    bW = kernel.w;
    if(aW < bW || aH < bH){
        fprintf(stderr,"Image cannot have smaller dimensions than the blur kernel");
    }

    for(r = aH-1;r >= 0;r--){
        for(c = aW-1;c >= 0;c--){
            temp = 0;
            for(y = bH-1;y >= 0;y--){
                yy = bH - y -1;
                for(x = bW-1;x >= 0;x--){
                    xx = bW - x - 1;
                    X = c + (x - (bW/2));
                    Y = r + (y - (bH/2));
                    if(X >= 0 && X < aW && Y >= 0 && Y < aH){
                        temp += ((kernel.data[(yy*bW)+xx])*(image.data[(Y*aW)+X]));
                    }
                }
            }
            conv.data[(r*aW)+c] = temp;
        }
    }
    return conv;
}

I reproduced this function in Matlab and found that it overestimates the values for certain pixels as compared to the regular 2D Convolution function in Matlab (conv2D). I can't figure out where I am going wrong with the logic. Please help.

EDIT: Here's the stock image I am using (512*512): https://drive.google.com/file/d/0B3qeTSY-DQRvdWxCZWw5RExiSjQ/view?usp=sharing

Here's the kernel (3*3): https://drive.google.com/file/d/0B3qeTSY-DQRvdlQzamcyVmtLVW8/view?usp=sharing

On using the above function I get

46465 46456 46564
45891 46137 46158
45781 46149 46030

But Matlab's conv2 gives me

46596 46618 46627
46073 46400 46149
45951 46226 46153

for the same pixels (rows:239-241,col:316:318)

This is the Matlab code I am using to compare the values:

pgm_img = imread('path\to\lena512.pgm');
kernel = imread('path\to\test_kernel.pgm');
sz_img = size(pgm_img);
sz_ker = size(kernel);
conv = conv2(double(pgm_img),double(kernel),'same');
pgm_img = padarray(pgm_img,floor(0.5*sz_ker),'both');
convolve = zeros(sz_img);
for i=floor(0.5*sz_ker(1))+1:floor(0.5*sz_ker(1))+sz_img(1)
    for j=floor(0.5*sz_ker(2))+1:floor(0.5*sz_ker(2))+sz_img(2)
        startX = j - floor(sz_ker(2)/2);
        startY = i - floor(sz_ker(1)/2);
        endX = j + floor(sz_ker(2)/2);
        endY = i + floor(sz_ker(1)/2);
        block = pgm_img(startY:endY,startX:endX);
        prod = double(block).*double(kernel);
        convolve(i-floor(0.5*sz_ker(1)),j-floor(0.5*sz_ker(2))) = sum(sum(prod));
    end
end
disp(conv(239:241,316:318));
disp(convolve(239:241,316:318));

One obvious difference is that your c code uses ints, while the matlab code uses doubles. Change your c code to use doubles, and see if the results are still different.

I created Image Convolution library for simple cases of an image which is a simple 2D Float Array.

The function supports arbitrary kernels and verified against MATLAB's implementation.

So all needed on your side is calling it with your generated Kernel.

You can use its generated DLL inside MATLAB and see it yields same results as MATLAB's Image Convolution functions.

Image Convolution - GitHub .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM