使用 SDL 的 C 语言中的高斯模糊

Gaussian blur in C using SDL

提问人:ImDaronned 提问时间:10/30/2023 最后编辑:ImDaronned 更新时间:11/2/2023 访问量:105

问:

我正在尝试使用 SDL 在 C 中创建高斯模糊。

这是我的函数:

我们承认参数是灰度图像(这就是为什么我只使用 )。surfacer

SDL_Surface* gaussian_blur(SDL_Surface* surface) {
    int w = surface->w;
    int h = surface->h;

    SDL_Surface* res = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);

   
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            Uint8 r = 0;

            for (int i = -2; i <= 2; i++) {
                for (int j = -2; j <= 2; j++) {
                    Uint32 pixel = get_pixel(surface, x+i, y+j);
                    double weight = core[i+2][j+2];

                    r += pixel*weight;
                }
            }

            Uint32 nPixel = SDL_MapRGB(res->format, r, r, r);
            put_pixel(res, x, y, nPixel); 
        }
    }

    free_surface(surface);
    return res;
}

我的核心被定义为:

double core[KERNEL_SIZE][KERNEL_SIZE] = {
    {1.0/273.0, 4.0/273.0, 7.0/273.0, 4.0/273.0, 1.0/273.0},
    {4.0/273.0, 16.0/273.0, 26.0/273.0, 16.0/273.0, 4.0/273.0},
    {7.0/273.0, 26.0/273.0, 41.0/273.0, 26.0/273.0, 7.0/273.0},
    {4.0/273.0, 16.0/273.0, 26.0/273.0, 16.0/273.0, 4.0/273.0},
    {1.0/273.0, 4.0/273.0, 7.0/273.0, 4.0/273.0, 1.0/273.0}
};
Uint32 get_pixel(SDL_Surface* surface, int x, int y) {
    int w = surface->w;
    int h = surface->h;

    if (surface != NULL && x >= 0 && x < w && y >= 0 && y < h) {
        Uint32* pixels = (Uint32*)surface->pixels;
        return pixels[y * w + x];
    }
    return 0;
}

void put_pixel(SDL_Surface* surface, int x, int y, Uint32 pixel) {
    int w = surface->w;
    int h = surface->h;
    
    if (surface != NULL && x >= 0 && x < w && y >= 0 && y < h) {
        Uint32* pixels = (Uint32*)surface->pixels;
        pixels[y * w + x] = pixel;
    }
}

图片是函数的结果:函数的结果

我在不同的网站上搜索过,但我找不到任何可以帮助我的东西。

我不能使用 MATHLAB 或 OpenCV。我只能使用 SDL

如果有人对如何去做有任何想法,我很想听听你的意见。

C 图像处理 SDL 高斯 模糊

评论

0赞 Marco Bonelli 10/30/2023
在 8:30 观看 3blue1brown 的这段视频,你可能会更好地理解你需要做什么: youtu.be/KuXjwB4LzSA?feature=shared&t=515 - 不过,内核肯定需要规范化。
0赞 AKX 10/30/2023
你没有除以权重的总和,所以你会超出范围。r
1赞 Cris Luengo 10/30/2023
r是一个 8 位整数。它溢出了。很多。以较大的类型累加,并在赋值为像素之前除以内核的总和。该值是由 RGB 三元组返回的吗?您需要分别对每个通道进行卷积,因此需要将 R、G 和 B 值分开,并在卷积中分别累加。get_pixel
1赞 Cris Luengo 10/30/2023
请不要将答案编辑到您的问题中。相反,请将其作为实际答案发布在下面。然后接受答案以指示问题具有有效的解决方案。
1赞 Cris Luengo 10/30/2023
新代码使用超出范围的坐标进行调用。get_pixel

答:

-1赞 ImDaronned 11/2/2023 #1

我的get_pixel给了我所有的颜色(r、g 和 b)。 所以我只需要涂上一个面膜(&0xFF)就可以获得正确的颜色。

有更正:

Uint8 pixel_color(SDL_Surface* surface, int w, int h, int x, int y) {
    Uint8 r = 0;

    for (int i = -2; i <= 2; i++) {
        for (int j = -2; j <= 2; j++) {
            Uint32 pixel = get_pixel(surface, x+i, y+j);
            Uint8 pixel_color = pixel & 0xFF; //HERE
            double weight = core[i+2][j+2];

            int nX = x+i, nY = y+j; 

            if (nX >= 0 && nX < w && nY >= 0 && nY < h)
                r += pixel_color*weight;
            else
                r += weight*255;
        }
    }

    return r;
}

SDL_Surface* gaussian_blur(SDL_Surface* surface) {
    int w = surface->w;
    int h = surface->h;

    SDL_Surface* res = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);

   
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            
            Uint8 color = pixel_color(surface, w, h, x, y);

            Uint32 nPixel = SDL_MapRGB(res->format, color, color, color);
            put_pixel(res, x, y, nPixel); 
        }
    }

    free_surface(surface);
    return res;
}