You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:C语言实现Sobel边缘检测时遭遇Segmentation Fault错误

Sobel边缘检测实现中的段错误问题

我尝试用C语言编写edge函数实现Sobel边缘检测,但程序每次运行都会触发Segmentation Fault错误。以下是我的源代码,实在找不到问题所在:

edges函数代码

void edges(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // Detect pixels along the edges and corners
            if ((i == 0 || i == height - 1) && (j == 0 || j == width - 1))
            {
                // For pixels at the top-left corner
                if (i == 0 && j == 0)
                {
                    loop_parameter_2(i, j, 2, 2, height, width, image, i, j);
                }

                // For pixels at the top-right corner
                else if (i == 0 && j == width - 1)    
                {
                    loop_parameter_2(i, j - 1, 2, 2, height, width, image, i, j);
                }

                // For pixels at the buttom-left corner
                else if (i == height - 1 && j == 0)    
                {
                    loop_parameter_2(i - 1, j, 2, 2, height, width, image, i, j);
                }

                // For pixels at the buttom-right corner
                else if (i == height - 1 && j == width - 1)    
                {
                    loop_parameter_2(i - 1, j - 1, 2, 2, height, width, image, i, j);
                }

                // For pixels along the top edges
                else if (i == 0 && j > 0 && j < width - 1)
                {
                    loop_parameter_2(i, j - 1, 2, 3, height, width, image, i, j);
                }

                // For pixels along the buttom edges
                else if (i == height - 1 && j > 0 && j < width - 1)
                {
                    loop_parameter_2(i - 1, j - 1, 2, 3, height, width, image, i, j);
                }
                
                // For pixels along the left edges
                else if (j == 0 && i > 0 && i < height - 1)
                {
                    loop_parameter_2(i - 1, j, 3, 2, height, width, image, i, j);
                }
                
                // For pixels along the right edges
                else if (j == width - 1 && i > 0 && i < height - 1)
                {
                    loop_parameter_2(i - 1, j - 1, 3, 2, height, width, image, i, j);
                }
            }
            else 
            {
                loop_parameter_2(i - 1, j - 1, 3, 3, height, width, image, i, j);
            }
        }
        
    }
    return;
}

loop_parameter_2函数代码

void loop_parameter_2(int height, int width, int times_to_loop1, int times_to_loop2, int h, int w, RGBTRIPLE image[h][w], int i, int j)
{
    // Kernel for the x direction 
    int Gx[3][3] = {
        {-1, 0, 1},
        {-2, 0, 2},
        {-1, 0, 1}
    };

    // Kernel for the y direction
    int Gy[3][3] = {
        {-1, -2, -1},
        {0, 0, 0},
        {1, 2, 1}
    };

    int t1;
    int t2;
    // Detect pixels along the edges and corners
    if ((i == 0 || i == height - 1) && (j == 0 || j == width - 1))
    {
        // For pixels at the top-left corner
        if (i == 0 && j == 0)
        {
            t1 = 1;
            t2 = 1;
        }

        // For pixels at the top-right corner and top edges
        else if ((i == 0 && j == width - 1) || (i == 0 && j > 0 && j < width - 1))    
        {
            t1 = 1;
            t2 = 0;
        }

        // For pixels at the buttom-left corner and left edges
        else if ((i == height - 1 && j == 0) || (j == 0 && i > 0 && i < height - 1))    
        {
            t1 = 0;
            t2 = 1;
        }
    }
    else
    {
        t1 = 0;
        t2 = 0;
    }

    // Variables to store weighted sums
    int sumRGx = 0;
    int sumRGy = 0;
    int sumGGx = 0;
    int sumGGy = 0;
    int sumBGx = 0;
    int sumBGy = 0;
    for (int a = height; a < height + times_to_loop1; a++)
    {
        for (int b = width; b < width + times_to_loop2; b++)
        {
            // Weighted sums for the red channel
            sumRGx += (image[a][b].rgbtRed * Gx[t1][t2]);
            sumRGy += (image[a][b].rgbtRed * Gy[t1][t2]);

            // Weighted sums for the green channel
            sumGGx += (image[a][b].rgbtGreen * Gx[t1][t2]);
            sumGGy += (image[a][b].rgbtGreen * Gy[t1][t2]);

            // Weighted sums for the blue channel
            sumBGx+= (image[a][b].rgbtBlue * Gx[t1][t2]);
            sumBGy += (image[a][b].rgbtBlue * Gy[t1][t2]);

            t2++;
        }
        t2 = 0;
        t1++;
    }

    image[i][j].rgbtRed = sqrt(sumRGx * sumRGx + sumRGy * sumRGy);
    image[i][j].rgbtGreen = sqrt(sumGGx * sumGGx + sumGGy * sumGGy);
    image[i][j].rgbtBlue = sqrt(sumBGx * sumBGx + sumBGy * sumBGy);
}

我曾尝试给Gx和Gy内核添加额外元素防止数组越界,但问题依旧。Valgrind能绕过段错误输出图像,但生成的图像非常模糊,完全无法辨识。


问题分析与修复方案

1. 参数命名冲突导致逻辑混乱

loop_parameter_2的前两个参数命名为height和width,但实际传递的是像素区域的起始坐标(比如edges传入的i、j-1等值),函数内部却用这两个参数判断i == height -1,导致逻辑完全错误。比如处理顶部边缘时,传入的height是0,此时判断i == -1,直接搞混了边缘逻辑,进而让t1、t2取值错误,最终引发数组越界。

修复:重命名这两个参数为start_row和start_col,避免和图像尺寸参数混淆。

2. 内核索引递增逻辑错误

loop_parameter_2中循环时直接递增t1、t2,但没有让图像遍历区域和内核区域一一对应。比如处理顶部角落时,应该只使用内核的右下角2x2区域,但当前代码会让t1从1递增到2,后续计算时内核索引和图像区域不匹配,导致加权求和完全错误。

修复:为每个遍历的图像像素对应正确的内核位置,比如遍历图像的start_row+a时,对应内核的kernel_start_row+a。

3. 直接修改原图像导致计算污染

计算Sobel边缘时直接修改原图像,后续像素会使用已修改的错误数据计算,最终导致图像模糊。

修复:创建临时图像副本保存原始数据,所有计算基于副本,最后将结果写回原图像。

4. 平方根结果未做截断处理

sqrt返回浮点数,而rgbtRed等是0-255的8位无符号整数,直接赋值会导致数值溢出或截断错误,需要将结果限制在合法范围内。

修复后的代码示例

修改后的edges函数

void edges(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++)
        {
            temp[i][j] = image[i][j];
        }
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int start_row, start_col;
            int loop_rows, loop_cols;
            int kernel_start_row, kernel_start_col;

            // 确定每个像素对应的遍历区域和内核起始位置
            if (i == 0 && j == 0)
            {
                // 左上角:遍历(0,0)-(1,1),对应内核(1,1)-(2,2)
                start_row = 0;
                start_col = 0;
                loop_rows = 2;
                loop_cols = 2;
                kernel_start_row = 1;
                kernel_start_col = 1;
            }
            else if (i == 0 && j == width - 1)
            {
                // 右上角:遍历(0,w-2)-(1,w-1),对应内核(1,0)-(2,1)
                start_row = 0;
                start_col = width - 2;
                loop_rows = 2;
                loop_cols = 2;
                kernel_start_row = 1;
                kernel_start_col = 0;
            }
            else if (i == height - 1 && j == 0)
            {
                // 左下角:遍历(h-2,0)-(h-1,1),对应内核(0,1)-(1,2)
                start_row = height - 2;
                start_col = 0;
                loop_rows = 2;
                loop_cols = 2;
                kernel_start_row = 0;
                kernel_start_col = 1;
            }
            else if (i == height - 1 && j == width - 1)
            {
                // 右下角:遍历(h-2,w-2)-(h-1,w-1),对应内核(0,0)-(1,1)
                start_row = height - 2;
                start_col = width - 2;
                loop_rows = 2;
                loop_cols = 2;
                kernel_start_row = 0;
                kernel_start_col = 0;
            }
            else if (i == 0)
            {
                // 顶部边缘:遍历(0,j-1)-(1,j+1),对应内核(1,0)-(2,2)
                start_row = 0;
                start_col = j - 1;
                loop_rows = 2;
                loop_cols = 3;
                kernel_start_row = 1;
                kernel_start_col = 0;
            }
            else if (i == height - 1)
            {
                // 底部边缘:遍历(h-2,j-1)-(h-1,j+1),对应内核(0,0)-(1,2)
                start_row = height - 2;
                start_col = j - 1;
                loop_rows = 2;
                loop_cols = 3;
                kernel_start_row = 0;
                kernel_start_col = 0;
            }
            else if (j == 0)
            {
                // 左侧边缘:遍历(i-1,0)-(i+1,1),对应内核(0,1)-(2,2)
                start_row = i - 1;
                start_col = 0;
                loop_rows = 3;
                loop_cols = 2;
                kernel_start_row = 0;
                kernel_start_col = 1;
            }
            else if (j == width - 1)
            {
                // 右侧边缘:遍历(i-1,w-2)-(i+1,w-1),对应内核(0,0)-(2,1)
                start_row = i - 1;
                start_col = width - 2;
                loop_rows = 3;
                loop_cols = 2;
                kernel_start_row = 0;
                kernel_start_col = 0;
            }
            else
            {
                // 内部像素:遍历3x3区域,对应完整内核
                start_row = i - 1;
                start_col = j - 1;
                loop_rows = 3;
                loop_cols = 3;
                kernel_start_row = 0;
                kernel_start_col = 0;
            }

            // 调用计算函数,传入临时图像
            compute_sobel(i, j, start_row, start_col, loop_rows, loop_cols, kernel_start_row, kernel_start_col, height, width, temp, image);
        }
    }
    return;
}

新的compute_sobel函数(替代原loop_parameter_2)

void compute_sobel(int target_row, int target_col, int start_row, int start_col, int loop_rows, int loop_cols, int kernel_start_row, int kernel_start_col, int height, int width, RGBTRIPLE temp[height][width], RGBTRIPLE image[height][width])
{
    int Gx[3][3] = {
        {-1, 0, 1},
        {-2, 0, 2},
        {-1, 0, 1}
    };

    int Gy[3][3] = {
        {-1, -2, -1},
        {0, 0, 0},
        {1, 2, 1}
    };

    int sumRGx = 0, sumRGy = 0;
    int sumGGx = 0, sumGGy = 0;
    int sumBGx = 0, sumBGy = 0;

    for (int a = 0; a < loop_rows; a++)
    {
        for (int b = 0; b < loop_cols; b++)
        {
            int img_row = start_row + a;
            int img_col = start_col + b;
            int kernel_row = kernel_start_row + a;
            int kernel_col = kernel_start_col + b;

            sumRGx += temp[img_row][img_col].rgbtRed * Gx[kernel_row][kernel_col];
            sumRGy += temp[img_row][img_col].rgbtRed * Gy[kernel_row][kernel_col];

            sumGGx += temp[img_row][img_col].rgbtGreen * Gx[kernel_row][kernel_col];
            sumGGy += temp[img_row][img_col].rgbtGreen * Gy[kernel_row][kernel_col];

            sumBGx += temp[img_row][img_col].rgbtBlue * Gx[kernel_row][kernel_col];
            sumBGy += temp[img_row][img_col].rgbtBlue * Gy[kernel_row][kernel_col];
        }
    }

    // 计算梯度并截断到0-255
    int red = sqrt(sumRGx * sumRGx + sumRGy * sumRGy);
    int green = sqrt(sumGGx * sumGGx + sumGGy * sumGGy);
    int blue = sqrt(sumBGx * sumBGx + sumBGy * sumBGy);

    image[target_row][target_col].rgbtRed = (red > 255) ? 255 : red;
    image[target_row][target_col].rgbtGreen = (green > 255) ? 255 : green;
    image[target_row][target_col].rgbtBlue = (blue > 255) ? 255 : blue;
}

内容的提问来源于stack exchange,提问作者Sylvester Adade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:07:00