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

CS50 Week4 Filter模块:Blur与Edges函数计算结果异常求助

图像模糊与边缘检测代码缺陷排查

模糊(Blur)实现要求

  • 实现盒式模糊(box blur)效果:每个像素的新颜色值为其3×3邻域内(含自身)所有像素对应颜色值的平均值
  • 边缘/角落像素仅取有效邻域内的像素计算平均

边缘检测(Edges)实现要求

  • 采用Sobel算子:对每个像素的RGB通道分别计算Gx、Gy加权和,再通过√(Gx²+Gy²)得到最终值
  • 结果需取整并限制在0-255范围内
  • 图像边缘外视为黑色像素(RGB值为0)

问题描述

代码无语法错误,但Blur和Edges函数计算结果不符合预期,无法定位具体问题,请求排查代码缺陷。

原代码

void calculateAverage(int height, int width, RGBTRIPLE image[height][width], int i, int j) {
    int sumR = 0;
    int sumG = 0;
    int sumB = 0;
    int count = 0;

    for (int row = i - 1; row <= i + 1; row++) {
        for (int col = j - 1; col <= j + 1; col++) {
            // Check if the indices are within bounds
            if (row >= 0 && row < height && col >= 0 && col < width) {
                sumR += image[row][col].rgbtRed;
                sumG += image[row][col].rgbtGreen;
                sumB += image[row][col].rgbtBlue;
                count++;

            }
        }
    }
    // Avoid division by zero
    if (count > 0) {
        image[i][j].rgbtRed = sumR / count;
        image[i][j].rgbtGreen = sumG / count;
        image[i][j].rgbtBlue = sumB / count;

    }
}

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            calculateAverage(height, width, image, i, j);
        }
    }
    return;
}

int gxgy(int narray[3][3])
{
    int gx[][3] = {
        {-1, 0, 1},
        {-2, 0, 2},
        {-1, 0, 1}};

    int gxsum = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            gxsum += narray[i][j] * gx[i][j];
        }
    }

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

    int gysum = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            gysum += narray[i][j] * gy[i][j];
        }
    }

    double gradientMagnitude = sqrt(pow(gxsum, 2) + pow(gysum, 2));
    int result = gradientMagnitude + 0.5;
    return (result > 255)? 255 : result;
}

void edgedetection(int height, int width, RGBTRIPLE image[height][width], int i, int j)
{
    int garry[3][3];
    int rarry[3][3];
    int barry[3][3];

    for (int row = i - 1, ni = 0; row <= i + 1; row++, ni++) {
        for (int col = j - 1, nj = 0; col <= j + 1; col++, nj++) {
            // Check if the neighbor is within bounds
            if (row >= 0 && row < height && col >= 0 && col < width) {
                garry[ni][nj] = image[row][col].rgbtRed;
                rarry[ni][nj] = image[row][col].rgbtGreen;
                barry[ni][nj] = image[row][col].rgbtBlue;
            } else {
                garry[ni][nj] = 0;
                rarry[ni][nj] = 0;
                barry[ni][nj] = 0;
            }
        }
    }

    image[i][j].rgbtRed = gxgy(rarry);
    image[i][j].rgbtGreen = gxgy(garry);
    image[i][j].rgbtBlue = gxgy(barry);
}

// Detect 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++)
        {
            edgedetection(height, width, image, i, j);
        }
    }
    return;
}

代码缺陷排查与修复

Blur函数核心问题

直接修改原图像导致计算污染:遍历计算模糊值时,直接修改了原图像的像素数据。后续像素计算会使用已被修改的像素值(而非原始图像数据),导致模糊结果严重偏差。

修复方案:先创建原图像的副本,所有计算基于副本数据,最后将结果写回原图像。

Edges函数核心问题

  1. 通道赋值颠倒:edgedetection函数中,将红色通道值赋值给了绿色通道数组,绿色通道值赋值给了红色通道数组,导致RGB通道的Sobel计算完全错误。
  2. 同样存在原图像污染问题:计算边缘时直接修改原图像,后续像素使用已修改的数据计算,结果失真。

其他细节优化

  • gxgy函数中,用整数乘法替代pow函数计算平方,避免不必要的浮点数开销与精度问题;同时用long long存储平方结果,防止int溢出。

修正后的代码

修正后的Blur函数

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    // 创建原图像副本
    RGBTRIPLE copy[height][width];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            copy[i][j] = image[i][j];
        }
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int sumR = 0;
            int sumG = 0;
            int sumB = 0;
            int count = 0;

            for (int row = i - 1; row <= i + 1; row++)
            {
                for (int col = j - 1; col <= j + 1; col++)
                {
                    if (row >= 0 && row < height && col >= 0 && col < width)
                    {
                        sumR += copy[row][col].rgbtRed;
                        sumG += copy[row][col].rgbtGreen;
                        sumB += copy[row][col].rgbtBlue;
                        count++;
                    }
                }
            }

            image[i][j].rgbtRed = sumR / count;
            image[i][j].rgbtGreen = sumG / count;
            image[i][j].rgbtBlue = sumB / count;
        }
    }
    return;
}

修正后的Edges函数

// Detect edges
void edges(int height, int width, RGBTRIPLE image[height][width])
{
    // 创建原图像副本
    RGBTRIPLE copy[height][width];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            copy[i][j] = image[i][j];
        }
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int rarry[3][3];
            int garry[3][3];
            int barry[3][3];

            for (int row = i - 1, ni = 0; row <= i + 1; row++, ni++)
            {
                for (int col = j - 1, nj = 0; col <= j + 1; col++, nj++)
                {
                    if (row >= 0 && row < height && col >= 0 && col < width)
                    {
                        rarry[ni][nj] = copy[row][col].rgbtRed;
                        garry[ni][nj] = copy[row][col].rgbtGreen;
                        barry[ni][nj] = copy[row][col].rgbtBlue;
                    }
                    else
                    {
                        rarry[ni][nj] = 0;
                        garry[ni][nj] = 0;
                        barry[ni][nj] = 0;
                    }
                }
            }

            image[i][j].rgbtRed = gxgy(rarry);
            image[i][j].rgbtGreen = gxgy(garry);
            image[i][j].rgbtBlue = gxgy(barry);
        }
    }
    return;
}

优化后的gxgy函数

int gxgy(int narray[3][3])
{
    int gx[3][3] = {
        {-1, 0, 1},
        {-2, 0, 2},
        {-1, 0, 1}};

    int gxsum = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            gxsum += narray[i][j] * gx[i][j];
        }
    }

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

    int gysum = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            gysum += narray[i][j] * gy[i][j];
        }
    }

    // 用long long避免平方后int溢出
    long long gx_sq = (long long)gxsum * gxsum;
    long long gy_sq = (long long)gysum * gysum;
    double gradientMagnitude = sqrt(gx_sq + gy_sq);
    int result = (int)(gradientMagnitude + 0.5);
    return (result > 255) ? 255 : result;
}

内容的提问来源于stack exchange,提问作者JW Ngiam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:55:58