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: