实现Box Blur滤镜时触发Invalid read of size 1错误,求修复方案
修复方框模糊滤镜的段错误问题
我正在尝试为图像实现Box Blur(方框模糊)滤镜,核心逻辑是计算目标像素周围9个相邻像素的RGB平均值,再将新RGB值赋值给原像素。我创建了temp[][]像素数组,编写嵌套循环算法完成计算,但运行时出现段错误(Segmentation Fault)。使用Valgrind检测后得到以下结果:
void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp[height][width];// creating temp array for blurred image //cycles for looping through the image for (int i=0; i < height; i++) { for (int j=0; j < width; j++) { int counter = 0; // amount of valid pixels float red = 0; float blue = 0; float green = 0; for (int k=i-1; k < i + 2; k++) // 3*3 square for adjacent pixels rows { if(i < 0 || i>= height ) // avoiding seg fault { continue; }else { for (int p=j-1; p < j+2; p++) // 3*3 square for adjacent pixels cols { if(j < 0 || j >= width ) // avoiding seg fault { continue; }else {// counting averages for 3*3 matrix red += image[k][p].rgbtRed; blue += image[k][p].rgbtBlue; green += image[k][p].rgbtGreen; counter++; } } } } // calculating averages red = round(red/counter); blue = round(blue/counter); green = round(green/counter); // assigning blurred values for temp array temp[i][j].rgbtRed = red; temp[i][j].rgbtBlue = blue; temp[i][j].rgbtGreen = green; } } for (int i=0; i < height; i++) { for (int j=0; j < width; j++) { image[i][j].rgbtRed = temp[i][j].rgbtRed ; image[i][j].rgbtBlue = temp[i][j].rgbtBlue ; image[i][j].rgbtGreen = temp[i][j].rgbtGreen; } } return; }
Valgrind检测输出:
filter-more/ $ valgrind ./filter -b images/yard.bmp OUTFILE.bmp ==28342== Memcheck, a memory error detector ==28342== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==28342== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==28342== Command: ./filter -b images/yard.bmp OUTFILE.bmp ==28342== ==28342== Invalid read of size 1 ==28342== at 0x109B4A: blur (helpers.c:78) ==28342== by 0x10953A: main (filter.c:105) ==28342== Address 0x4b744bf is 1 bytes before a block of size 720,000 alloc'd ==28342== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==28342== by 0x109425: main (filter.c:78) ==28342== ==28342== Invalid read of size 1 ==28342== at 0x109B7C: blur (helpers.c:79) ==28342== by 0x10953A: main (filter.c:105) ==28342== Address 0x4b744bd is 3 bytes before a block of size 720,000 alloc'd ==28342== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==28342== by 0x109425: main (filter.c:78) ==28342== ==28342== Invalid read of size 1 ==28342== at 0x109BAD: blur (helpers.c:80) ==28342== by 0x10953A: main (filter.c:105) ==28342== Address 0x4b744be is 2 bytes before a block of size 720,000 alloc'd ==28342== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==28342== by 0x109425: main (filter.c:78) ==28342== ==28342== ==28342== HEAP SUMMARY: ==28342== in use at exit: 0 bytes in 0 blocks ==28342== total heap usage: 5 allocs, 5 frees, 729,136 bytes allocated ==28342== ==28342== All heap blocks were freed -- no leaks are possible ==28342== ==28342== For lists of detected and suppressed errors, rerun with: -s ==28342== ERROR SUMMARY: 720000 errors from 3 contexts (suppressed: 0 from 0)
问题根源
你的边界判断完全错误:
- 行越界判断用的是外层循环的
i,但实际应该检查当前遍历的3x3区域行索引k - 列越界判断用的是外层循环的
j,但实际应该检查当前遍历的3x3区域列索引p
i和j本身已经在0<=i<height、0<=j<width的合法范围内,所以这些判断永远不会触发。当处理图像边缘像素时,k会取到-1(比如i=0时)或height(比如i=height-1时),p会取到-1或width,直接访问了数组的非法内存区域,引发段错误。
修复后的代码
void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp[height][width];// 创建存储模糊后图像的临时数组 // 遍历图像每个像素 for (int i=0; i < height; i++) { for (int j=0; j < width; j++) { int counter = 0; // 有效像素计数 float red = 0; float blue = 0; float green = 0; // 遍历当前像素周围3x3区域的行 for (int k=i-1; k < i + 2; k++) { // 检查行索引k是否越界 if(k < 0 || k >= height ) { continue; } // 遍历当前像素周围3x3区域的列 for (int p=j-1; p < j+2; p++) { // 检查列索引p是否越界 if(p < 0 || p >= width ) { continue; } // 累加RGB值 red += image[k][p].rgbtRed; blue += image[k][p].rgbtBlue; green += image[k][p].rgbtGreen; counter++; } } // 计算平均值并取整 red = round(red/counter); blue = round(blue/counter); green = round(green/counter); // 将模糊后的值存入临时数组 temp[i][j].rgbtRed = red; temp[i][j].rgbtBlue = blue; temp[i][j].rgbtGreen = green; } } // 将临时数组的结果复制回原图像 for (int i=0; i < height; i++) { for (int j=0; j < width; j++) { image[i][j].rgbtRed = temp[i][j].rgbtRed ; image[i][j].rgbtBlue = temp[i][j].rgbtBlue ; image[i][j].rgbtGreen = temp[i][j].rgbtGreen; } } return; }
额外优化建议
- 去掉多余的
else分支,continue已经会跳过后续代码,让逻辑更简洁 - 如果处理大尺寸图像,栈上的
temp数组可能导致栈溢出,建议改用malloc动态分配内存,使用完后记得调用free释放
内容的提问来源于stack exchange,提问作者VladislavSapozhnikov
相关产品推荐
相关产品推荐

