如何在数组中选取两个非对齐坐标之间的像素点
非共行/共列点连线的像素选取实现
选取两个非共行、非共列坐标之间的离散像素点,本质是低分辨率整数数组上的直线光栅化问题,不需要复杂的几何推导,有成熟的工程化实现方案可以直接落地,结合你提到的40x40数组、取[10,10]到[17,32]连线像素的场景,具体操作逻辑如下:
核心参数计算
首先把两个端点的坐标固定下来,计算基础差值与步进方向,避免取点偏离直线走向:
- 记两个端点为
(x0, y0)和(x1, y1),对应你举例的参数就是x0=10、y0=10,x1=17、y1=32 - 计算两个方向的坐标增量绝对值:
dx = abs(x1 - x0),dy = abs(y1 - y0),本例中dx=7,dy=22 - 计算两个方向的步进方向:
sx = 1 if x1 > x0 else -1,sy = 1 if y1 > y0 else -1,本例中两个方向的步进值都为1,因为终点坐标大于起点坐标
取点逻辑适配
因为两个方向的增量不一致,需要选择增量更大的方向作为主遍历方向,避免取点出现断层:
- 若dy > dx(如本例dy=22远大于dx=7),固定沿着y方向逐点遍历,总遍历次数等于dy+1,每移动一个y步,通过累计偏移量计算对应的x坐标,累计值取整后即为当前位置的像素坐标
- 若dx > dy,反过来沿着x方向逐点遍历,每步通过累计偏移量计算对应的y坐标
- 若dx = dy,即为45度斜线,每步x、y各步进1即可,不存在累计误差
可直接复用的成熟实现
上述累计取整的逻辑其实就是经典的Bresenham直线算法,完全用整数运算实现,没有浮点计算开销,非常适配数组像素操作的场景,简化后的通用实现如下:
def get_line_pixels(x0, y0, x1, y1): dx = abs(x1 - x0) dy = abs(y1 - y0) sx = 1 if x1 > x0 else -1 sy = 1 if y1 > y0 else -1 # 初始化误差变量 err = dx - dy points = [] while True: points.append((x0, y0)) # 碰到终点就停止 if x0 == x1 and y0 == y1: break e2 = 2 * err if e2 > -dy: err -= dy x0 += sx if e2 < dx: err += dx y0 += sy return points
针对你举的例子,直接调用get_line_pixels(10, 10, 17, 32),返回的元组列表就是两点连线上的所有有效像素坐标,可以直接用来索引数组取值。
特殊场景调整
- 如果要取从起点出发的半直线(沿直线方向延伸到数组边界),只需要把循环的停止条件从“碰到终点就停”改成“坐标超出40x40数组的边界就停”即可
- 不建议直接用斜率计算加四舍五入的方式取点,这种纯浮点取整的方案很容易在长斜线上出现像素错位,Bresenham的误差累积逻辑就是专门为了消除这个问题设计的,取点连续性远好于直接取整的方案
内容的提问来源于stack exchange,提问作者Coolcrab
相关产品推荐
相关产品推荐

