I am currently working on a project which is filtering a bmp file. This smoothing filter uses a 3x3 blurring kernel which is a fixed size small matrix. The convolution operation moves this kernel over the image, shifting it on pixel at a time and takes the dot product of matrix elements with the pixel values underneath. Basically this filter traverses the entire image to producing a single pixel out of 9 adjacent pixels.
In order to preserve the image size both horizontally and vertically, padding is added to the input image by adding 0 valued pixels around the edges of the image.
Related images can be seen on the links:
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
typedef struct{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
}rgb ;
void smoothing_filter(int height, int width, rgb **image, rgb **dest);
int main() {
    FILE *inputPtr;
    if ((inputPtr = fopen("starry_night.bmp", "rb+")) == NULL) {
        printf("The input file could not be opened\n");
    } else {
        BITMAPFILEHEADER fileheader_input;
        fread(&fileheader_input, sizeof(BITMAPFILEHEADER), 1, inputPtr);
        BITMAPINFOHEADER infoheader_input;
        fread(&infoheader_input, sizeof(BITMAPINFOHEADER), 1, inputPtr);
        if (fileheader_input.bfType != 0x4d42 || fileheader_input.bfOffBits != 54 ||
            infoheader_input.biSize != 40 || infoheader_input.biBitCount != 24 || infoheader_input.biCompression != 0) {
            fclose(inputPtr);
            printf("Unsupported input file.\n");
        } else {
            int height = abs(infoheader_input.biHeight);
            int width = infoheader_input.biWidth;
            rgb **rgb_array;
            rgb_array = calloc(height, sizeof(rgb *));
            for (int row = 0; row < height; ++row) {
                rgb_array[row] = calloc(width, sizeof(rgb));
            }
            for (int row = 0; row < height; row++) {
                for (int col = 0; col < width; ++col) {
                    fread(&rgb_array[row][col], sizeof(rgb), 1, inputPtr);
                }
            }
            infoheader_input.biWidth = width + 2;
            infoheader_input.biHeight = height + 2;
            fileheader_input.bfSize = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) +
                                      3 * abs(infoheader_input.biWidth) * abs(infoheader_input.biHeight);
            rewind(inputPtr);
            fwrite(&(fileheader_input), sizeof(BITMAPFILEHEADER), 1, inputPtr);
            fwrite(&(infoheader_input), sizeof(BITMAPINFOHEADER), 1, inputPtr);
            rgb blanckRgb = {0, 0, 0};
            for (int i = 0; i < (width + 2); ++i) {
                fwrite(&blanckRgb, sizeof(rgb), 1, inputPtr);
            }
            for (int row = 0; row < height; ++row) {
                fwrite(&blanckRgb, sizeof(rgb), 1, inputPtr);
                for (int col = 0; col < width; ++col) {
                    fwrite(&rgb_array[row][col].red, 1, 1, inputPtr);
                    fwrite(&rgb_array[row][col].green, 1, 1, inputPtr);
                    fwrite(&rgb_array[row][col].blue, 1, 1, inputPtr);
                }
                fwrite(&blanckRgb, sizeof(rgb), 1, inputPtr);
            }
            for (int i = 0; i < (width + 2); ++i) {
                fwrite(&blanckRgb, sizeof(rgb), 1, inputPtr);
            }
            FILE *outputPtr;
            if ((outputPtr = fopen("starry_night_filtered.bmp", "wb")) == NULL) {
                printf("The \"starry_night_filtered.bmp\" file could not be created\n");
            }else{
                BITMAPFILEHEADER fileheader_output = fileheader_input;
                BITMAPINFOHEADER infoheader_output = infoheader_input;
                infoheader_output.biWidth = width;
                infoheader_output.biHeight = height;
                fileheader_output.bfSize = sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER)+3*abs(width*height);
                fwrite(&(fileheader_output), sizeof(BITMAPFILEHEADER), 1, outputPtr);
                fwrite(&(infoheader_output), sizeof(BITMAPINFOHEADER), 1, outputPtr);
                rgb **image;
                image = calloc(infoheader_input.biHeight, sizeof(rgb *));
                for (int row = 0; row < infoheader_input.biHeight; ++row) {
                    image[row] = calloc(infoheader_input.biWidth, sizeof(rgb));
                }
                rewind(inputPtr);
                for (int row = 0; row < infoheader_input.biHeight; row++) {
                    for (int col = 0; col < infoheader_input.biWidth; col++) {
                        fread(&image[row][col], sizeof(rgb), 1, inputPtr);
                    }
                }
                rgb **dest;
                dest = calloc(height, sizeof(rgb *));
                for (int row = 0; row < height; ++row) {
                    dest[row] = calloc(width, sizeof(rgb));
                }
                smoothing_filter(infoheader_input.biHeight, infoheader_input.biWidth, image, dest);
                for (int row = 0; row < height; row++) {
                    for (int col = 0; col < width; col++) {
                        fwrite(&dest[row][col], sizeof(rgb), 1, outputPtr);
                    }
                }
                free(image);
                free(rgb_array);
                fclose(outputPtr);
                fclose(inputPtr);
            }
        }
    }
}
void smoothing_filter(int height, int width, rgb **image, rgb **dest)
{
    double redVal, blueVal, greenVal;
    // Iterate through rows
    for (int row = 0; row < (height-2); row++)
    {
        // Iterate through columns
        for (int col = 0; col < (width-2); col++)
        {
            // Obtain RGB values of current image pixel
            redVal = (0.0625*image[row][col].red) + (0.125*image[row][col+1].red) + (0.0625*image[row][col+2].red)
                     +(0.125*image[row+1][col].red) + (0.25*image[row+1][col+1].red) + (0.125*image[row+1][col+2].red)
                     +(0.0625*image[row+2][col].red) + (0.125*image[row+2][col+1].red) + (0.0625*image[row+2][col+2].red);
            greenVal = (0.0625*image[row][col].green) + (0.125*image[row][col+1].green) + (0.0625*image[row][col+2].green)
                       +(0.125*image[row+1][col].green) + (0.25*image[row+1][col+1].green) + (0.125*image[row+1][col+2].green)
                       +(0.0625*image[row+2][col].green) + (0.125*image[row+2][col+1].green) + (0.0625*image[row+2][col+2].green);
            blueVal = (0.0625*image[row][col].blue) + (0.125*image[row][col+1].blue) + (0.0625*image[row][col+2].blue)
                      +(0.125*image[row+1][col].blue) + (0.25*image[row+1][col+1].blue) + (0.125*image[row+1][col+2].blue)
                      +(0.0625*image[row+2][col].blue) + (0.125*image[row+2][col+1].blue) + (0.0625*image[row+2][col+2].blue);
            dest[row][col].red = (int) redVal;
            dest[row][col].green = (int) greenVal;
            dest[row][col].blue = (int) blueVal;
        }
    }
}
THE PROBLEM:
My code works okay except somehow it shifts an image a little bit to the right. I could not find the reason of it. Can you help me about that. Thanks in advance Output of my codes:
 
    