使用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
相关产品推荐
相关产品推荐

