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

基于二维数组实现PGM/PPM文件圆绘制的技术问询

完成PGM图像的圆形绘制函数实现

你的代码目前有几个需要调整的地方:循环范围固定到50会导致只在图像的小区域绘制,而且pow的使用不仅有性能开销,还可能引入浮点精度问题。下面我给你两种实现方案,分别适合不同的场景:

方案一:简单距离判断法(易理解,适合入门)

这个方法遍历图像的每一个像素,计算它到圆心的距离平方(避免开根号,提升性能),如果距离在半径范围内就设置对应的灰度值。代码逻辑非常直观:

// 不需要额外引入math.h,用整数乘法代替pow
void drawCircle(unsigned char pgmImage[][WIDTH], int height, int centerX, int centerY, int radius, unsigned char grayLevel) {
    // 遍历整个图像的所有行
    for (int rowIndex = 0; rowIndex < height; rowIndex++) {
        // 遍历当前行的所有列
        for (int colIndex = 0; colIndex < WIDTH; colIndex++) {
            // 计算当前像素与圆心的横向、纵向偏移量
            int dx = colIndex - centerX;
            int dy = rowIndex - centerY;
            
            // 用平方比较代替开根号,避免浮点运算的开销和精度误差
            if (dx * dx + dy * dy <= radius * radius) {
                pgmImage[rowIndex][colIndex] = grayLevel;
            }
        }
    }
}

方案特点:

  • 优点:逻辑简单,新手很容易理解和调试
  • 缺点:需要遍历图像所有像素,对于超大图像性能会稍差;如果要画空心圆,只需把条件改成dx*dx + dy*dy <= radius*radius && dx*dx + dy*dy >= (radius-1)*(radius-1)

方案二:中点圆算法(高性能,适合复杂场景)

如果你的图像尺寸很大,或者需要绘制大量圆形,推荐用中点圆算法——它只需要遍历圆的1/8区域,然后通过对称性绘制所有点,性能提升非常明显:

void drawCircle(unsigned char pgmImage[][WIDTH], int height, int centerX, int centerY, int radius, unsigned char grayLevel) {
    int x = radius;
    int y = 0;
    int err = 0;

    // 先做边界检查:确保圆心在图像范围内,避免数组越界
    if (centerX < 0 || centerX >= WIDTH || centerY < 0 || centerY >= height) {
        return;
    }

    // 先绘制圆的四个对称轴上的点
    if (centerX + x < WIDTH) pgmImage[centerY][centerX + x] = grayLevel;
    if (centerX - x >= 0) pgmImage[centerY][centerX - x] = grayLevel;
    if (centerY + x < height) pgmImage[centerY + x][centerX] = grayLevel;
    if (centerY - x >= 0) pgmImage[centerY - x][centerX] = grayLevel;

    // 遍历圆的1/8区域,通过八对称性绘制所有点
    while (x > y) {
        y++;
        err += 2 * y + 1;

        if (err > 0) {
            x--;
            err -= 2 * x + 1;
        }

        // 绘制第一象限及对称的7个象限的点
        if (x >= y) {
            // 第一组对称点
            if (centerX + x < WIDTH && centerY + y < height) pgmImage[centerY + y][centerX + x] = grayLevel;
            if (centerX - x >= 0 && centerY + y < height) pgmImage[centerY + y][centerX - x] = grayLevel;
            if (centerX + x < WIDTH && centerY - y >= 0) pgmImage[centerY - y][centerX + x] = grayLevel;
            if (centerX - x >= 0 && centerY - y >= 0) pgmImage[centerY - y][centerX - x] = grayLevel;

            // 当x≠y时,绘制另一组对称点(避免重复绘制对角线点)
            if (x != y) {
                if (centerX + y < WIDTH && centerY + x < height) pgmImage[centerY + x][centerX + y] = grayLevel;
                if (centerX - y >= 0 && centerY + x < height) pgmImage[centerY + x][centerX - y] = grayLevel;
                if (centerX + y < WIDTH && centerY - x >= 0) pgmImage[centerY - x][centerX + y] = grayLevel;
                if (centerX - y >= 0 && centerY - x >= 0) pgmImage[centerY - x][centerX - y] = grayLevel;
            }
        }
    }
}

方案特点:

  • 优点:计算量小,性能远高于遍历所有像素的方法;天然是绘制空心圆的逻辑
  • 缺点:逻辑稍复杂,需要理解圆的八对称性原理;如果要画实心圆,需要额外添加扫描线填充的逻辑

额外注意事项:

  • 不管用哪种方案,都要做好边界检查,确保绘制的像素坐标不会超出图像的height(行范围0到height-1)和WIDTH(列范围0到WIDTH-1),避免数组越界导致程序崩溃
  • 如果要适配PPM彩色图像,只需要把数组类型改成三维数组(比如unsigned char ppmImage[][WIDTH][3]),然后设置对应的RGB分量即可,核心的圆绘制逻辑是完全一致的

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:00:48