BMP文件过滤器像素调整 / C语言

发布于 2025-02-13 12:22:24 字数 7272 浏览 2 评论 0原文

我目前正在研究一个正在过滤BMP文件的项目。 该平滑过滤器使用3x3模糊的内核,该内核是固定尺寸的小矩阵。 卷积操作将此内核移到图像上,一次将其移动在像素上,并将矩阵元素的点产物带有下面的像素值。基本上,此滤波器遍历整个图像,从而产生9个相邻像素的单个像素。

为了水平和垂直保持图像大小,通过在图像边缘周围添加0个值的像素,将填充物添加到输入图像中。

相关图像可以在链接上看到:

卷积操作图像

填充操作

这是我的代码:

#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;
        }
    }
}

问题:

我的代码正常运行,除了以某种方式将图像向右移动。 我找不到原因。你能帮我吗? 提前致谢 我的代码的输出:

input imput image

输出图像

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:

convolution operation image

padding operation

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:

Input image

output image

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七颜 2025-02-20 12:22:24

这可能不是出现问题的原因,但是由于几个原因,此代码是有问题的:

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);
    }
}
  • 您不选择2D数组,而是指针表,因此代码不必要地慢慢慢,因为没有充分的理由。每个呼叫Calloc都会创建零散的内存。详细信息:正确分配多维阵列
  • 而不是malloc使代码不必要地出于没有充分的理由而慢,因为您打算立即覆盖内存而且您没有Calloc的零初始化的好处。
  • fread(&amp; rgb_array [row] [col],sizeof(rgb),1,inputptr); 没有充分的理由,因为您一次读取一个项目。文件I/O通常是瓶颈,因此应将其最小化。如果使用了2D数组,则可以一口气读取文件。
  • 始终检查callocfread的结果。

而是考虑这样的东西:

rgb (*rgb_array)[width] ; // pointer to the first item in a rgb[height][width] 2D array

rgb_array = malloc( sizeof(rgb[height][width]) ); // one single call
if(rgb_array == NULL) { /* error handling */ }

size_t result = fread(rgb_array, sizeof(rgb), height*width, inputPtr); // one single call
if(result != height*width) { /* error handling */ }

...
free(rgb_array); // one single call

您需要相应地更改功能,让它们接受2D数组:

void smoothing_filter(int height, 
                      int width, 
                      rgb image[height][width], 
                      rgb dest[height][width]);

This might not be the cause of the problem, but this code is problematic for several reasons:

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);
    }
}
  • You don't allocate a 2D array but a pointer table, so the code turns needlessly slow for no good reason. Each call to calloc will create fragmented memory. Details here: Correctly allocating multi-dimensional arrays
  • Using calloc instead of malloc makes the code needlessly slow for no good reason, since you intend to immediately overwrite the memory anyway and you have no benefit of calloc's zero initialization.
  • fread(&rgb_array[row][col], sizeof(rgb), 1, inputPtr); is very slow for no good reason, since you read one single item at a time. File I/O is usually a bottleneck so it should be minimized. If you used 2D arrays you could read the file in one go.
  • Always check the result of calloc and fread.

Consider something like this instead:

rgb (*rgb_array)[width] ; // pointer to the first item in a rgb[height][width] 2D array

rgb_array = malloc( sizeof(rgb[height][width]) ); // one single call
if(rgb_array == NULL) { /* error handling */ }

size_t result = fread(rgb_array, sizeof(rgb), height*width, inputPtr); // one single call
if(result != height*width) { /* error handling */ }

...
free(rgb_array); // one single call

You'll need to change your functions accordingly, to have them accept 2D arrays instead:

void smoothing_filter(int height, 
                      int width, 
                      rgb image[height][width], 
                      rgb dest[height][width]);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文