基于二维数组实现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
相关产品推荐
相关产品推荐

