You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SDL在C语言中实现高斯模糊遇到问题求助

SDL+C实现高斯模糊的问题排查与修正

尝试用SDL在C语言中实现高斯模糊功能,输入为灰度图像(仅使用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 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;
}

卷积核定义

#define KERNEL_SIZE 5
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;
    }
}

核心问题分析

  • 未提取正确通道值:get_pixel返回完整32位像素值,直接参与计算会包含RGB+Alpha的多字节数据,导致数值溢出或错误,必须单独提取R通道灰度值。
  • 累加变量类型错误:用Uint8存储累加结果会截断小数部分且易溢出,需用高精度类型(如double)暂存。
  • 边界处理不当:超出图像范围的像素直接返回0,导致边缘区域变暗,应采用边界复制策略(取最近有效像素)。
  • 边界场景权重归一化缺失:边缘区域无法取到完整5x5核时,原归一化系数不再适用,需重新计算有效权重总和并归一化。

修正后的实现

新增通道提取函数(含边界处理)

Uint8 get_pixel_r(SDL_Surface* surface, int x, int y) {
    int w = surface->w;
    int h = surface->h;
    // 边界处理:超出范围时取最近的有效像素坐标
    x = (x < 0) ? 0 : (x >= w) ? w-1 : x;
    y = (y < 0) ? 0 : (y >= h) ? h-1 : y;
    
    Uint32 pixel = ((Uint32*)surface->pixels)[y * w + x];
    Uint8 r;
    SDL_GetRGB(pixel, surface->format, &r, NULL, NULL);
    return r;
}

修正后的高斯模糊函数

SDL_Surface* gaussian_blur(SDL_Surface* surface) {
    int w = surface->w;
    int h = surface->h;
    const int kernel_radius = 2;
    SDL_Surface* res = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
    if (!res) return NULL;

    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            double sum_r = 0.0;
            double weight_sum = 0.0;

            for (int i = -kernel_radius; i <= kernel_radius; i++) {
                for (int j = -kernel_radius; j <= kernel_radius; j++) {
                    int nx = x + i;
                    int ny = y + j;
                    if (nx >= 0 && nx < w && ny >=0 && ny < h) {
                        Uint8 r = get_pixel_r(surface, nx, ny);
                        double weight = core[i + kernel_radius][j + kernel_radius];
                        sum_r += r * weight;
                        weight_sum += weight;
                    }
                }
            }
            // 归一化处理,避免除以0
            if (weight_sum > 0) {
                sum_r /= weight_sum;
            }
            // 限制数值在0-255范围内,防止溢出
            Uint8 final_r = (sum_r < 0) ? 0 : (sum_r > 255) ? 255 : (Uint8)sum_r;
            Uint32 nPixel = SDL_MapRGB(res->format, final_r, final_r, final_r);
            put_pixel(res, x, y, nPixel);
        }
    }

    free_surface(surface);
    return res;
}

内容的提问来源于stack exchange,提问作者ImDaronned

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:40:00