图像滤波代码
#includestdio.h#includestdlib.h#includemath.h// 5阶拉普拉斯核二维转一维按行优先存储 5×5 → 25元素intlaplacian_5x5_1d[]{0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0};#defineKERNEL_SIZE5// 核尺寸5×5#defineKERNEL_LEN25// 一维核总长度// 计算一维卷积核的权重总和归一化核心intcalc_kernel_sum_1d(){intsum0;for(inti0;iKERNEL_LEN;i){sumlaplacian_5x5_1d[i];}// 避免除以0若总和为0取1returnsum0?1:sum;}/** * 读取P5格式PGM图像自动解析宽高、最大灰度值 * param filename: PGM文件路径 * param width: 输出图像宽度自动获取 * param height: 输出图像高度自动获取 * param max_val: 输出最大灰度值通常255 * return: 像素数组unsigned char*失败返回NULL */unsignedchar*read_p5_pgm(constchar*filename,int*width,int*height,int*max_val){FILE*fpfopen(filename,rb);if(!fp){fprintf(stderr,错误无法打开文件 %s\n,filename);returnNULL;}// 1. 校验魔数必须是P5charmagic[3];fscanf(fp,%s,magic);if(magic[0]!P||magic[1]!5){fprintf(stderr,错误仅支持P5格式二进制PGM文件\n);fclose(fp);returnNULL;}// 2. 跳过注释行以#开头charc;while((cfgetc(fp))#){while(fgetc(fp)!\n);// 跳过整行注释}ungetc(c,fp);// 把非#字符放回缓冲区// 3. 自动读取宽、高、最大灰度值if(fscanf(fp,%d %d %d,width,height,max_val)!3){fprintf(stderr,错误PGM文件头解析失败\n);fclose(fp);returnNULL;}fgetc(fp);// 跳过最后一个分隔符换行/空格// 4. 分配像素内存intpixel_count(*width)*(*height);unsignedchar*pixels(unsignedchar*)malloc(pixel_count*sizeof(unsignedchar));if(!pixels){fprintf(stderr,错误内存分配失败\n);fclose(fp);returnNULL;}// 5. 读取二进制像素数据P5格式核心if(fread(pixels,sizeof(unsignedchar),pixel_count,fp)!pixel_count){fprintf(stderr,错误像素数据读取失败\n);free(pixels);fclose(fp);returnNULL;}fclose(fp);returnpixels;}/** * 5阶拉普拉斯滤波处理一维卷积核 归一化 * param src: 输入像素数组一维 * param width/height: 图像宽高自动获取的数值 * return: 滤波后像素数组一维 */unsignedchar*laplacian_5x5_filter_1d(constunsignedchar*src,intwidth,intheight){intpaddingKERNEL_SIZE/2;// 5×5核需要2像素边缘填充intpixel_countwidth*height;unsignedchar*dst(unsignedchar*)malloc(pixel_count*sizeof(unsignedchar));if(!dst)returnNULL;// 计算核权重总和归一化因子intkernel_sumcalc_kernel_sum_1d();// 遍历图像跳过边缘padding区域避免越界for(intypadding;yheight-padding;y){for(intxpadding;xwidth-padding;x){intsum0;// 遍历一维卷积核计算卷积核心二维坐标转一维索引for(intky0;kyKERNEL_SIZE;ky){// 核的行for(intkx0;kxKERNEL_SIZE;kx){// 核的列// 1. 一维核索引行优先 → ky*KERNEL_SIZE kxintkernel_idxky*KERNEL_SIZEkx;// 2. 图像像素索引(当前行核行偏移)×宽度 (当前列核列偏移)intimg_yy-paddingky;intimg_xx-paddingkx;intsrc_idximg_y*widthimg_x;// 3. 卷积累加核权重 × 像素值sumlaplacian_5x5_1d[kernel_idx]*src[src_idx];}}// 卷积结果归一化除以核权重总和sumsum/kernel_sum;// 溢出保护 灰度值映射到0-255sumsum255?255:(sum0?0:sum);dst[y*widthx](unsignedchar)sum;}}// 边缘区域填充为0for(inti0;ipixel_count;i){intyi/width;intxi%width;if(ypadding||yheight-padding||xpadding||xwidth-padding){dst[i]0;}}returndst;}/** * 保存P5格式PGM图像 * param filename: 输出路径 * param pixels: 像素数组一维 * param width/height/max_val: 图像参数自动获取的数值 */voidsave_p5_pgm(constchar*filename,constunsignedchar*pixels,intwidth,intheight,intmax_val){FILE*fpfopen(filename,wb);if(!fp){fprintf(stderr,错误无法保存文件 %s\n,filename);return;}// 写入P5文件头fprintf(fp,P5\n%d %d\n%d\n,width,height,max_val);// 写入二进制像素数据fwrite(pixels,sizeof(unsignedchar),width*height,fp);fclose(fp);}// 主函数演示使用intmain(intargc,char*argv[]){if(argc!3){printf(使用方法%s 输入P5 PGM文件 输出P5 PGM文件\n,argv[0]);return1;}// 1. 读取PGM自动获取宽高intwidth,height,max_val;unsignedchar*src_pixelsread_p5_pgm(argv[1],width,height,max_val);if(!src_pixels)return1;printf(PGM解析成功宽度%d高度%d最大灰度值%d\n,width,height,max_val);printf(一维拉普拉斯核权重总和%d归一化因子\n,calc_kernel_sum_1d());// 2. 5阶拉普拉斯滤波一维核 归一化unsignedchar*dst_pixelslaplacian_5x5_filter_1d(src_pixels,width,height);if(!dst_pixels){free(src_pixels);return1;}// 3. 保存滤波结果save_p5_pgm(argv[2],dst_pixels,width,height,max_val);printf(滤波完成一维核结果已保存至 %s\n,argv[2]);// 释放内存free(src_pixels);free(dst_pixels);return0;}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2408592.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!