【算法学习】高斯模糊算法

/// <summary>  
/// 程序功能:c语言实现纯高斯模糊
/// 系统Ubuntu 15.10,GCC开发环境,编程语言C,最新整理时间 whd 2016.9.2。  
/// 参考代码:https://github.com/Duwaz/Gaussian_Blur
/// <remarks> 1: 能处理24位BMP格式图像。</remarks>    
/// <remarks> 2: 主程序无参数,默认处理工程目录下的input.bmp,处理后的结果为output.bmp。</remarks>    
/// <remarks> 3: 处理效果由高斯模糊半径决定:GaussBlur(bmp_t*, double)函数的第二个参数</remarks> 
/// </summary> 
#include<stdio.h>  
#include<stdlib.h>
#include<malloc.h>
#include <math.h>
#define SQRT_2PI 2.506628274631
//自定义数据类型
typedef unsigned long       DWORD; //四个字节
typedef int                 BOOL;
typedef unsigned char       BYTE; //一个字节
typedef unsigned short      WORD; //一个字节
//位图信息头结构体定义
typedef struct tagBITMAPINFOHEADER
{
   WORD   bfType;  //两个字节
   DWORD  bfileSize;
   DWORD  bfReserved;
   DWORD  bOffBits;
   DWORD  biSize;   //4个字节
   long   biWidth;  //4个字节
   long   biHeight;
   WORD   biPlanes;
   WORD   biBitCount;
   DWORD  biCompression;
   DWORD  biSizeImage;
   long   biXPelsPerMeter;
   long   biYPelsPerMeter;
   DWORD biClrUsed;
   DWORD biClrImportant;
} __attribute__((packed))BITMAPINFOHEADER,*PBITMAPINFOHEADER;  //字节对齐
typedef struct
{
	BITMAPINFOHEADER header;  //信息头
	char *data;//图像数据
} bmp_t;
int win_size(double);  
double Gauss(double, double);
void bmp_free(bmp_t *);
bmp_t *bmp_open(FILE *);
int bmp_write(bmp_t*, FILE*);
bmp_t *GaussBlur(bmp_t*, double);
int main(void)  
{  
        char *InputName, *OutputName;  //输入输出图像文件名变量
	FILE *InputFile, *OutputFile;  //输入输出图像文件
	bmp_t *bmp = NULL, *blur = NULL;
        InputName = "input.bmp"; OutputName = "output.bmp";
        if(!(InputFile=fopen(InputName, "r")))  //图像文件打开函数,打不开返回,提示找不到文件
	{
		printf("File not found\n");
		return 1;
	}
        bmp = bmp_open(InputFile);   //图像文件读取操作,前面必须有打开的操作才能读取文件数据
	fclose(InputFile);//关闭文件
        OutputFile = fopen(OutputName, "wb"); //打开并创建输出文件
        if (OutputFile == NULL) 
        {
		printf("Can't open %s\n", OutputName);
		return 1;
	}
        blur = GaussBlur(bmp, 4.0); //模糊处理并返回处理后数据
        bmp_write(blur, OutputFile);//将处理后数据存放到新建的文件中 
        fclose(OutputFile); //关闭文件
        bmp_free(bmp);//释放存放读取数据的内存
        free(blur);//释放处理后图像数据的内存
        return 0;
}  
/// <summary>  
/// 函数功能:给定一个BMP图像文件,将其中的数据读取出来,并返回图像数据  
/// 函数返回:图像的数据(信息头和数据)
/// 知识点:如何读取一个图像文件的数据 
/// </summary>  
/// <param name="f">图像文件存放位置地址。</param>  
bmp_t *bmp_open(FILE *f) 
{
	bmp_t *bmp;
	bmp = (bmp_t *)malloc(sizeof(bmp_t));
	bmp->data = NULL;

	if (fread(&(bmp->header), sizeof(BITMAPINFOHEADER), 1, f)) {
		bmp->data = (char*)malloc(bmp->header.biSizeImage);
		if (fread(bmp->data, bmp->header.biSizeImage, 1, f))
                 printf("图像读取成功\n");
                 printf("Width: %ld\n", bmp->header.biWidth);
                 printf("Height: %ld\n", bmp->header.biHeight);
                 printf("BitCount: %d\n\n", (int)bmp->header.biBitCount);
			return bmp;
	}
	fprintf(stderr, "Error reading file");
	bmp_free(bmp);
	return NULL;
}
/// <summary>  
/// 函数功能:释放存放图像数据的内存  
/// 函数返回:无
/// 知识点:释放图像数据内存 
/// </summary>  
/// <param name="bmp">图像数据变量。</param>  
void bmp_free(bmp_t *bmp)
{
	if (bmp == NULL) return;
	if (bmp->data != NULL) free(bmp->data);
	free(bmp);
}
/// <summary>  
/// 函数功能:将图像数据写入到图像文件中  
/// 函数返回:写入数据的个数
/// 知识点:将数据写入文件中(将数值从内存写入文件中)
/// </summary>  
/// <param name="bmp">图像数据变量。</param>  
/// <param name="out">文件流。</param>  
int bmp_write(bmp_t *bmp, FILE *out) {
	return fwrite(&(bmp->header), sizeof(BITMAPINFOHEADER), 1, out)
		&& fwrite(bmp->data, bmp->header.biSizeImage, 1, out);
}
/// <summary>  
/// 函数功能:模糊窗的大小(根据高斯半径和模糊半径满足3sigma原则) 
/// 函数返回:模糊窗的大小,即长或宽(长=宽)
/// 知识点:高斯模糊的3*sigma原则
/// </summary>  
/// <param name="sigma">高斯核函数的参数sigma</param>  
int win_size(double sigma)
{
	return (1 + (((int)ceil(3 * sigma)) * 2)); 
}
/// <summary>  
/// 函数功能:单像素点计算高斯系数 
/// 函数返回:高斯系数
/// 知识点:高斯系数计算公式
/// </summary>  
/// <param name="sigma">高斯核函数的参数sigma</param>  
/// <param name="x">当前像素距离模糊窗中心的距离</param>  
double Gauss(double sigma, double x)
{
	return exp(-(x * x) / (2.0 * sigma * sigma)) / (sigma * SQRT_2PI);
}
/// <summary>  
/// 函数功能:计算高斯模糊窗下的每个像素对应的权值,计算一半就够了,因为是权值是对称的(一维高斯)
/// 函数返回:模糊窗下每个像素的权值
/// 知识点:模糊窗下的各点的高斯系数(一维数组)
/// </summary>  
/// <param name="sigma">高斯核函数的参数sigma</param>  
/// <param name="win_size">模糊窗的大小</param>  
double* GaussAlgorithm(int win_size, double sigma)
{
	int wincenter, x;
	double *kern, sum = 0.0;
	wincenter = win_size / 2;
	kern = (double*)calloc(win_size, sizeof(double));

	for (x = 0; x < wincenter + 1; x++)
	{
		kern[wincenter - x] = kern[wincenter + x] = Gauss(sigma, x);
		sum += kern[wincenter - x] + ((x != 0) ? kern[wincenter + x] : 0.0);
	}
	for (x = 0; x < win_size; x++)
		kern[x] /= sum;

	return kern;
}
/// <summary>  
/// 函数功能:高斯模糊实现函数
/// 函数返回:模糊后的图像
/// 知识点:模糊窗下的各点的高斯系数(数组)
/// </summary>  
/// <param name="src">待模糊的图像</param>  
/// <param name="sigma">模糊半径(高斯核函数参数)</param>  
/// <remarks> rgb三通道分别处理</remarks> 
bmp_t *GaussBlur(bmp_t *src, double sigma) 
{
	int	row, col, col_r, col_g, col_b, winsize, halfsize, k, count, rows, count1, count2, count3;
	int width, height;
	double  row_g, row_b, row_r, col_all;
	unsigned char  r_r, r_b, r_g, c_all;
	char *tmp;
	double *algorithm;

	count=0;
	width = 3*src->header.biWidth; height = src->header.biHeight;

	if ((width % 4) != 0) width += (4 - (width % 4)); 
	bmp_t *blur;
	blur = (bmp_t*)malloc(sizeof(bmp_t));
	blur->header = src->header;
	blur->header.biWidth = src->header.biWidth;
	blur->header.biHeight = src->header.biHeight;
	blur->header.biSizeImage = width * blur->header.biHeight;
	blur->data = (char*)malloc(blur->header.biSizeImage);

	winsize = win_size(sigma);
	algorithm = GaussAlgorithm(winsize, sigma); 
	winsize *= 3; 
	halfsize = winsize / 2;

	tmp = (char*)calloc(width * height, sizeof(char)); 
	
	for (row = 0; row < height; row++)
	{
		col_r = 0;
		col_g = 1;
		col_b = 2;
		for (rows = 0; rows < width; rows += 3)
		{
			row_r = row_g = row_b = 0.0;
			count1 = count2 = count3 = 0;
		
			for (k = 1; k < winsize; k += 3)
			{
				if ((k + col_r - halfsize >= 0) && (k + col_r - halfsize < width))
				{
					r_r = *(src->data + row * width + col_r + k - halfsize);
					row_r += (int)(r_r)* algorithm[count1];
					count1++;
				}
				if ((k + col_g - halfsize >= 0) && (k + col_g - halfsize < width))
				{
					r_g = *(src->data + row * width + col_g + k - halfsize);
					row_g += (int)(r_g)* algorithm[count2];
					count2++;
				}

				if ((k + col_b - halfsize >= 0) && (k + col_b - halfsize < width))
				{
					r_b = *(src->data + row * width + col_b + k - halfsize);
					row_b += (int)(r_b)* algorithm[count3];
					count3++;
				}
			}

			*(tmp + row * width + col_r) = (unsigned char)(ceil(row_r));
			*(tmp + row * width + col_g) = (unsigned char)(ceil(row_g));
			*(tmp + row * width + col_b) = (unsigned char)(ceil(row_b));
			col_r += 3;
			col_g += 3;
			col_b += 3;
		}
	}
	
	winsize /= 3;
	halfsize = winsize / 2;
	for (col = 0; col < width; col++)
		for (row = 0; row < height; row++)
		{
		col_all = 0.0;
		for (k = 0; k < winsize; k++)
			if ((k + row - halfsize >= 0) && (k + row - halfsize < height))
			{
			c_all = *(tmp + (row + k - halfsize) * width + col);
			col_all += ((int)c_all) * algorithm[k];
			}
		*(blur->data + row * width + col) = (unsigned char)(ceil(col_all));
		}
	
	free(tmp);
	free(algorithm);

	return blur;
}

算法处理效果:sigma=4.0



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌三角猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值