高斯滤波图像处理
采集的是32x32 热成像数据,下面是原始数据
3051 3045 3041 3041 3054 3029 3054 3033 3035 3034 3034 3035 3035 3038 3041 3026 3041 3034 3041 3025 3037 3018 3014 3002 3018 3025 3019 3002 3017 3008 3024 3018
3055 3041 3039 3043 3034 3023 3045 3035 3031 3034 3040 3022 3048 3041 3048 3058 3055 3056 3041 3044 3028 3022 3019 3023 3022 3015 3004 3032 3029 3009 3013 3023
3054 3041 3054 3041 3029 3054 3040 3041 3034 3050 3027 3048 3063 3062 3053 3056 3052 3050 3057 3051 3051 3033 3033 3031 3018 3004 3007 3021 3016 3016 3024 3039
3030 3044 3040 3042 3042 3033 3044 3047 3034 3039 3061 3061 3064 3071 3059 3056 3049 3050 3052 3056 3054 3032 3031 3022 3016 3013 3029 3021 3026 3030 3016 3005
2980 2982 2994 2997 2998 2991 3001 3001 2990 3009 3007 3010 3017 3018 3034 3032 3035 3036 3024 3027 3016 3004 3021 3001 3015 3012 3012 3020 3013 3011 3026 3021
2992 2983 2990 2989 3003 3007 3000 2997 2995 3009 3007 3012 3033 3032 3042 3043 3033 3027 3035 3035 3018 3008 3020 3007 3013 3020 3024 3024 3016 2999 3017 3029
2997 2989 2994 2997 2998 3000 3021 3015 3007 3024 3023 3039 3048 3057 3028 3044 3039 3041 3048 3031 3032 3040 3023 3037 3041 3041 3035 3038 3029 3031 3020 3029
2992 2999 3009 2982 3002 3007 3017 3023 3024 3033 3043 3043 3053 3052 3052 3053 3053 3057 3040 3035 3046 3028 3020 3019 3015 3027 3031 3024 3015 3022 3029 3030
3017 2994 2998 3009 3007 3008 3016 3023 3032 3043 3056 3071 3078 3086 3056 3065 3069 3068 3056 3044 3039 3033 3042 3022 3020 3024 3023 3016 3024 3020 3002 3020
3013 3011 3013 3009 3010 3009 3023 3026 3051 3048 3060 3083 3080 3090 3099 3093 3089 3092 3087 3050 3043 3055 3034 3036 3031 3023 3024 3009 3007 3001 3016 3007
3008 3008 3024 3027 3011 3010 3023 3041 3047 3052 3084 3071 3087 3095 3101 3104 3108 3106 3087 3057 3037 3034 3052 3054 3036 3014 3020 3016 3009 3003 3002 3031
3006 3012 3014 3006 3022 3010 3019 3035 3038 3060 3062 3095 3112 3104 3104 3091 3107 3099 3086 3050 3049 3040 3049 3046 3051 3030 3018 3010 3020 3017 3022 3029
3012 3015 3012 3014 3020 3010 3022 3034 3044 3053 3064 3097 3097 3101 3101 3095 3094 3098 3092 3073 3049 3046 3050 3058 3051 3040 3022 3022 3017 3023 3020 3029
3017 3017 3029 3011 3013 3009 3026 3036 3041 3048 3104 3099 3107 3102 3094 3106 3105 3103 3091 3088 3055 3055 3073 3059 3057 3024 3014 3018 3004 3017 3013 3005
3013 3028 3031 3018 3003 3018 3018 3036 3041 3056 3098 3094 3081 3107 3105 3114 3107 3103 3109 3093 3077 3084 3090 3086 3053 3038 3020 3027 3001 3025 3020 3009
3029 3016 3020 3019 3019 3002 3006 3013 3052 3081 3103 3093 3091 3094 3096 3115 3104 3099 3103 3093 3108 3101 3103 3094 3056 3026 3031 3032 3019 3032 3010 3017
3027 3024 3006 3007 3012 2997 3010 3004 3040 3076 3090 3097 3089 3094 3105 3103 3097 3112 3102 3095 3096 3085 3087 3086 3052 3022 3024 3012 3014 3024 3011 3023
3024 3029 3033 3037 3020 2994 2999 3009 3053 3080 3084 3095 3097 3088 3105 3104 3105 3100 3106 3104 3103 3101 3099 3097 3068 3031 3018 3016 3017 3025 3018 3016
3025 3018 3016 3025 3015 3015 3008 3011 3036 3071 3093 3092 3096 3092 3091 3100 3113 3103 3101 3100 3102 3101 3103 3089 3042 3026 3041 3018 3017 3021 3026 3009
3016 3024 3012 3015 3014 3001 2996 3004 3022 3075 3080 3095 3091 3095 3109 3100 3104 3099 3103 3105 3108 3103 3089 3089 3040 3019 3008 3012 3021 3012 3012 3023
3009 3021 3018 3024 3003 2998 2999 3009 2999 3069 3083 3086 3093 3095 3099 3090 3091 3108 3108 3099 3096 3087 3098 3056 3026 3029 3015 2998 3009 3014 3023 3017
3015 3017 3010 3002 3012 3008 3015 3010 3005 3036 3080 3097 3093 3101 3108 3096 3098 3108 3093 3106 3094 3097 3092 3035 3015 3019 3017 3010 3018 3019 3023 3011
3016 3006 3004 3003 3012 3011 3003 3003 3006 3018 3080 3079 3082 3087 3092 3091 3090 3100 3099 3092 3093 3086 3086 3026 3023 3017 3028 3037 3032 3007 3023 3034
3009 3006 3005 3013 2997 3005 2991 2996 2996 3010 3059 3086 3088 3099 3104 3107 3093 3102 3096 3091 3089 3094 3053 3016 3021 3012 3015 3033 3049 3029 3016 3033
2992 3023 3021 3002 3013 2991 2998 3002 2990 3010 3010 3076 3085 3092 3088 3095 3105 3102 3103 3095 3089 3088 3031 3019 3017 3015 3035 3035 3053 3031 3027 3030
2996 3027 3008 3005 3003 2999 2999 2998 3002 3014 3013 3051 3086 3094 3094 3096 3106 3102 3098 3082 3092 3061 3024 3015 3022 3014 3038 3041 3059 3041 3041 3022
3015 2996 3019 3006 3005 3003 3002 2990 2991 3004 3011 3050 3086 3091 3080 3089 3090 3107 3099 3092 3101 3067 3041 3021 3022 3034 3041 3033 3056 3052 3029 3067
2989 3006 2995 3001 2992 3005 2997 3006 3019 3009 3011 3040 3085 3093 3087 3093 3094 3096 3088 3089 3084 3076 3035 3020 3014 3031 3015 3023 3045 3062 3054 3047
3005 3018 3011 3023 3022 3031 3038 3048 3058 3065 3089 3093 3093 3103 3091 3088 3088 3104 3101 3097 3092 3101 3100 3076 3062 3072 3062 3058 3069 3060 3076 3060
3002 3025 3037 3056 3045 3052 3058 3065 3072 3080 3100 3090 3097 3097 3085 3083 3105 3102 3096 3097 3104 3101 3091 3081 3071 3069 3066 3068 3083 3071 3081 3064
3038 3043 3051 3054 3071 3078 3062 3061 3063 3086 3086 3090 3099 3096 3095 3089 3106 3097 3093 3087 3092 3084 3095 3071 3082 3083 3089 3085 3078 3083 3078 3075
3042 3071 3065 3064 3078 3073 3064 3064 3074 3075 3089 3076 3094 3107 3096 3089 3083 3092 3097 3092 3078 3096 3084 3079 3080 3086 3101 3080 3072 3098 3086 3082
- 上述中的数据复制粘贴到data.txt 注意格式32*32,每个数据之间空格
- 读取data.txt数据,高斯滤波后的数据写入xlsx文件,使用色阶 红-黄-绿 即可看到滤波后的图像
c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "xlsxwriter.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define IMG_SIZE 32
#define KERNEL_SIZE 7
// 生成高斯核,kernel 为 KERNEL_SIZE x KERNEL_SIZE 的二维数组,sigma 为标准差
void createGaussianKernel(float kernel[KERNEL_SIZE][KERNEL_SIZE], float sigma) {
int i, j;
int half = KERNEL_SIZE / 2;
float sum = 0.0f;
float s = 2.0f * sigma * sigma;
for (i = 0; i < KERNEL_SIZE; i++) {
for (j = 0; j < KERNEL_SIZE; j++) {
int x = i - half;
int y = j - half;
kernel[i][j] = expf(-(x * x + y * y) / s) / (M_PI * s);
sum += kernel[i][j];
}
}
// 归一化高斯核
for (i = 0; i < KERNEL_SIZE; i++) {
for (j = 0; j < KERNEL_SIZE; j++) {
kernel[i][j] /= sum;
}
}
}
// 对输入图像进行高斯滤波(数据以一维数组存储,长度为 IMG_SIZE*IMG_SIZE)
// 这里先将 uint16_t 数据转换为 float 进行计算,计算结果再转换回 uint16_t
void applyGaussianFilter(const uint16_t input_uint16[], uint16_t output_uint16[], float kernel[KERNEL_SIZE][KERNEL_SIZE]) {
float input[IMG_SIZE * IMG_SIZE];
float output[IMG_SIZE * IMG_SIZE];
int i, j, m, n;
int half = KERNEL_SIZE / 2;
// 将输入数据转换为 float
for (i = 0; i < IMG_SIZE * IMG_SIZE; i++) {
input[i] = (float)input_uint16[i];
}
// 进行高斯滤波
for (i = 0; i < IMG_SIZE; i++) {
for (j = 0; j < IMG_SIZE; j++) {
float sum = 0.0f;
for (m = 0; m < KERNEL_SIZE; m++) {
for (n = 0; n < KERNEL_SIZE; n++) {
int x = i + m - half;
int y = j + n - half;
if (x >= 0 && x < IMG_SIZE && y >= 0 && y < IMG_SIZE) {
sum += input[x * IMG_SIZE + y] * kernel[m][n];
}
}
}
output[i * IMG_SIZE + j] = sum;
}
}
// 将滤波结果转换回 uint16_t,并进行必要的截断处理(例如舍入到最近的整数)
for (i = 0; i < IMG_SIZE * IMG_SIZE; i++) {
if (output[i] < 0.0f)
output_uint16[i] = 0;
else if (output[i] > 65535.0f)
output_uint16[i] = 65535;
else
output_uint16[i] = (uint16_t)(output[i] + 0.5f); // 四舍五入
}
}
int main(void) {
uint16_t pixelData[IMG_SIZE * IMG_SIZE];
uint16_t filteredData[IMG_SIZE * IMG_SIZE];
float kernel[KERNEL_SIZE][KERNEL_SIZE];
float sigma = 1.0f; // 根据需要调整 sigma 值
// 打开 data.txt 文件读取原始数据
FILE *inputFile = fopen("data.txt", "r");
if (inputFile == NULL) {
perror("无法打开 data.txt 文件");
return EXIT_FAILURE;
}
// 读取 32×32 的数据(假设文件中数据以空白符分隔)
for (int i = 0; i < IMG_SIZE * IMG_SIZE; i++) {
if (fscanf(inputFile, "%hu", &pixelData[i]) != 1) {
fprintf(stderr, "读取数据失败,数据数量不足\n");
fclose(inputFile);
return EXIT_FAILURE;
}
}
fclose(inputFile);
// 生成高斯核
createGaussianKernel(kernel, sigma);
// 对数据应用高斯滤波
applyGaussianFilter(pixelData, filteredData, kernel);
// 使用 libxlsxwriter 生成 XLSX 文件
lxw_workbook *workbook = workbook_new("gaosi_output.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
// 可选:设置行高、列宽
for (int row = 0; row < IMG_SIZE; row++) {
worksheet_set_row(worksheet, row, 30, NULL);
}
worksheet_set_column(worksheet, 0, IMG_SIZE - 1, 5, NULL);
// 将滤波后的数据写入 XLSX 文件
for (int i = 0; i < IMG_SIZE; i++) {
for (int j = 0; j < IMG_SIZE; j++) {
// 这里将 uint16_t 转为 double 写入单元格
worksheet_write_number(worksheet, i, j, (double)filteredData[i * IMG_SIZE + j], NULL);
}
}
workbook_close(workbook);
printf("高斯滤波处理完成,结果已保存至 gaosi_output.xlsx\n");
return EXIT_SUCCESS;
}
编译:
gcc -o gaosi_process gaosi_process.c -lm -lxlsxwriter -lz
滤波前的图像显示如下: (头的右边头发盖住了)

滤波后的图像显示如下:
- 图像中可以看出滤波后的图像四个边角的数值最小偏差最大,以及边框的部分数值偏差也比较大

边缘和角落的数据偏差通常是由边缘处理方式造成的。在代码中,采用零填充(即超出图像范围的像素值视为 0)会导致在边缘和角落区域,卷积窗口内有效数据较少,从而使得滤波后的值偏小。
解决方法
采用边缘复制(replicate padding)或镜像填充(mirrored padding)
这种方法可以使得当卷积窗口超出图像范围时,用最近的边缘像素值来填充,而不是简单地用 0 填充。这样可以较好地保持边缘的亮度和信息。
- 更改函数applyGaussianFilter
c
// 对输入图像进行高斯滤波(数据以一维数组存储,长度为 IMG_SIZE*IMG_SIZE)
// 这里先将 uint16_t 数据转换为 float 进行计算,计算结果再转换回 uint16_t
void applyGaussianFilter(const uint16_t input_uint16[], uint16_t output_uint16[], float kernel[KERNEL_SIZE][KERNEL_SIZE]) {
float input[IMG_SIZE * IMG_SIZE];
float output[IMG_SIZE * IMG_SIZE];
int i, j, m, n;
int half = KERNEL_SIZE / 2;
// 将输入数据转换为 float
for (i = 0; i < IMG_SIZE * IMG_SIZE; i++) {
input[i] = (float)input_uint16[i];
}
// 进行高斯滤波
for (i = 0; i < IMG_SIZE; i++) {
for (j = 0; j < IMG_SIZE; j++) {
float sum = 0.0f;
for (m = 0; m < KERNEL_SIZE; m++) {
for (n = 0; n < KERNEL_SIZE; n++) {
int x = i + m - half;
int y = j + n - half;
// 复制边缘像素处理
if (x < 0)
x = 0;
else if (x >= IMG_SIZE)
x = IMG_SIZE - 1;
if (y < 0)
y = 0;
else if (y >= IMG_SIZE)
y = IMG_SIZE - 1;
sum += input[x * IMG_SIZE + y] * kernel[m][n];
}
}
output[i * IMG_SIZE + j] = sum;
}
}
// 将滤波结果转换回 uint16_t,并进行必要的截断处理(例如舍入到最近的整数)
for (i = 0; i < IMG_SIZE * IMG_SIZE; i++) {
if (output[i] < 0.0f)
output_uint16[i] = 0;
else if (output[i] > 65535.0f)
output_uint16[i] = 65535;
else
output_uint16[i] = (uint16_t)(output[i] + 0.5f); // 四舍五入
}
}
滤波后的图像显示,这时候边框部分没有明显的偏差了

滤波前后图像对比

原始图像下载 https://newbie-typora.oss-cn-shenzhen.aliyuncs.com/zhongke/output.xlsx
高斯图像下载 https://newbie-typora.oss-cn-shenzhen.aliyuncs.com/zhongke/gaosi_output.xlsx

高斯滤波参数调整影响:
高斯滤波在图像处理中是非常常见的平滑方法,它的"可调参数"会直接影响图像平滑的效果、边缘保留程度、噪声抑制能力等。以下是高斯滤波可调整的主要参数,以及每个参数调整后对结果的影响:
1. 高斯核大小(Kernel Size)
含义:卷积核的尺寸,比如 3×3、5×5、7×7、9×9 等。
- 小核(如 3×3) :
- 平滑效果较弱;
- 能保留更多细节;
- 抗噪能力较弱;
- 计算速度快。
- 大核(如 7×7 或 9×9) :
- 平滑效果更强;
- 会模糊细节(特别是边缘);
- 抗噪能力强;
- 计算开销更大。
通常建议:核大小设为奇数(如 3、5、7、9),并满足经验公式:
kernel_size ≈ 6 × sigma + 1
✅ 2. σ(Sigma,标准差)
含义:控制高斯函数的"扩散程度",影响核中每个像素的权重分布。
- 小 σ(如 0.5 ~ 1.0) :
- 高斯核权重集中在中心;
- 仅平滑邻近像素;
- 更好保留细节,模糊程度小。
- 大 σ(如 2.0 ~ 3.0) :
- 权重分布更宽;
- 模糊半径大;
- 更强的去噪效果,但可能过度模糊。
注意:即使核尺寸一样,调整 sigma 也能控制模糊程度。
✅ 3. 边缘处理方式(Padding Mode)
含义:当卷积窗口超出图像边界时如何处理:
- 零填充(Zero Padding) :
- 边缘可能变暗或失真;
- 快速简便,但对边缘不友好。
- 边缘复制(Replicate Padding) :
- 使用边界上的值填充;
- 可有效缓解边缘模糊变暗的问题。
- 镜像填充(Reflect Padding) :
- 像镜子一样反射边缘;
- 更自然的边界过渡,常用于图像处理。
✅ 4. 数据类型和精度
- 使用
uint8_t
、uint16_t
会丢失小数部分; - 使用
float
或double
可以更高精度地表达滤波结果; - 最终输出再根据需求量化为整数类型。
✅ 5. 滤波方式(单通道 / 多通道)
- 彩色图像需对每个通道分别滤波(RGB 分别处理);
- 可以选用更高级的颜色感知高斯滤波,如 bilateral filter(双边滤波)避免颜色混淆。
📝 可视化示例对比(描述性)
参数组合 | 效果说明 |
---|---|
核 3×3,σ = 0.5 | 稍微平滑,细节清晰 |
核 7×7,σ = 1.5 | 明显平滑,小物体边界模糊 |
核 9×9,σ = 3.0 | 强烈模糊,细节丢失但噪声干净 |
零填充 | 边缘明显偏暗 |
复制边缘填充 | 边缘平滑,自然过渡 |
✅ 推荐的调参策略
目标 | 推荐参数设置 |
---|---|
轻度降噪,细节保留 | 核 3×3 或 5×5,σ = 0.8 ~ 1.0 |
中度去噪 | 核 5×5 或 7×7,σ = 1.0 ~ 1.5 |
强烈平滑(模糊) | 核 7×7 或 9×9,σ = 2.0 ~ 3.0 |
避免边缘异常 | 使用"复制边缘"或"镜像填充" |
在处理低分辨率(32×32)的热成像数据时,目标通常是降低噪声的同时保留温度的梯度和局部特征。这里有一些调参建议:
- 核大小
- 推荐使用 3×3 或 5×5 核。
- 对于 32×32 的数据来说,过大的核(如 7×7 或更大)可能导致过度平滑,使得温度梯度模糊,降低局部细节的辨识度。
- σ(标准差)
- 建议选择较小到中等的 σ 值,比如 0.8~1.5。
- 较小的 σ 值可以减少模糊效应,保留更多的细节;若噪声较大,可适当增大 σ 值,但不要超过 1.5,否则可能丢失局部温差信息。
- 边缘处理
- 建议使用边缘复制或镜像填充而不是零填充。
- 32×32 图像中,边缘数据占比相对较大,复制边缘可以避免边界区域温度值明显偏低的问题。
- 噪声与细节权衡
- 由于热成像数据往往本身噪声较多,可适当进行平滑处理,但过度平滑可能掩盖真实温差。
- 可尝试先对比 3×3、σ=1.0 和 5×5、σ=1.0~1.5 的效果,再根据实际情况调整。
- 实验和反馈
- 对于热成像显示,建议进行几组参数试验:
- 3×3核、σ=0.8:保留细节但噪声可能较明显。
- 5×5核、σ=1.0:平滑效果较好且能保留温度梯度。
- 5×5核、σ=1.5:更强的平滑,但可能使局部温差减弱。
- 根据视觉显示效果选择最佳组合。
- 对于热成像显示,建议进行几组参数试验:
在 32×32 的低分辨率热成像中,推荐从 5×5 核和 σ 在 1.0 左右开始,配合边缘复制处理,然后根据图像噪声水平和温差细节适当微调参数。这样既能降低噪声,又能尽量保持温度变化信息,获得更自然的视觉显示效果。