cv2.circle绘制小半径圆呈菱形,全尺寸有尖刺,求高效绘制500万圆方案
兼顾精度与速度的大量圆形绘制方案
一、预生成高精度圆模板(推荐方案)
你的半径范围取整后是1-500,仅500种可能值。先一次性用skimage.draw.disk生成所有半径的掩码模板,后续绘制时直接复用模板,通过numpy内存切片赋值替代逐个调用绘图函数,既能保证skimage级别的精度,速度又能接近OpenCV。
实现步骤
- 预生成所有半径的布尔掩码模板,按半径值存储为字典
- 遍历待绘制的圆,根据半径取出模板,计算目标图像中的有效绘制区域(处理边界超出情况),将模板对应区域赋值为目标颜色
import numpy as np from skimage.draw import disk # 预生成1-500半径的圆模板 radius_templates = {} for r in range(1, 501): # 生成以(r,r)为中心、半径r的圆掩码,模板尺寸为(2r+1, 2r+1) rr, cc = disk((r, r), r, shape=(2*r+1, 2*r+1)) mask = np.zeros((2*r+1, 2*r+1), dtype=np.uint8) mask[rr, cc] = 1 radius_templates[r] = mask # 初始化目标图像(示例尺寸1000x1000,可替换为你的实际尺寸) H, W = 1000, 1000 target_img = np.zeros((H, W), dtype=np.uint8) # 模拟500万个圆的参数(实际替换为你的圆心、半径、颜色列表) np.random.seed(42) centers = np.random.randint(0, max(H, W), size=(5_000_000, 2)) radii = np.random.randint(1, 501, size=5_000_000) colors = np.random.randint(1, 256, size=5_000_000) # 按半径分组批量绘制,提升效率 for r in radius_templates: # 筛选当前半径的所有圆 radius_mask = radii == r if not np.any(radius_mask): continue current_centers = centers[radius_mask] current_colors = colors[radius_mask] template = radius_templates[r] half_size = r template_h, template_w = template.shape for (x, y), color in zip(current_centers, current_colors): # 计算模板在目标图像中的起止坐标 start_y, end_y = y - half_size, y + half_size + 1 start_x, end_x = x - half_size, x + half_size + 1 # 裁剪边界外的区域 target_y1, target_y2 = max(0, start_y), min(H, end_y) target_x1, target_x2 = max(0, start_x), min(W, end_x) template_y1, template_y2 = max(0, -start_y), template_h - max(0, end_y - H) template_x1, template_x2 = max(0, -start_x), template_w - max(0, end_x - W) # 仅在有效区域存在时绘制 if target_y1 < target_y2 and target_x1 < target_x2: target_region = target_img[target_y1:target_y2, target_x1:target_x2] template_region = template[template_y1:template_y2, template_x1:template_x2] target_region[template_region == 1] = color
方案优势
- 预生成模板仅执行一次,后续绘制全用numpy内存操作,速度远快于逐个调用
skimage.draw.disk - 模板由skimage生成,完全避免菱形、尖刺问题
- 按半径分组处理减少重复模板加载,进一步提升效率
二、混合方案:小半径用模板,大半径用OpenCV抗锯齿
若担心预生成500个模板占用内存(总内存约500MB,多数设备可承受),可针对小半径(如r≤10)用高精度模板,大半径用cv2.circle(..., lineType=cv2.LINE_AA)——大半径下OpenCV抗锯齿效果已足够接近正圆,且速度极快。
import numpy as np import cv2 from skimage.draw import disk # 预生成小半径(1-10)的模板 small_radius_templates = {} for r in range(1, 11): rr, cc = disk((r, r), r, shape=(2*r+1, 2*r+1)) mask = np.zeros((2*r+1, 2*r+1), dtype=np.uint8) mask[rr, cc] = 1 small_radius_templates[r] = mask H, W = 1000, 1000 target_img = np.zeros((H, W), dtype=np.uint8) # 模拟圆参数 centers = np.random.randint(0, max(H, W), size=(5_000_000, 2)) radii = np.random.randint(1, 501, size=5_000_000) colors = np.random.randint(1, 256, size=5_000_000) # 分两类处理 for (x, y), r, color in zip(centers, radii, colors): if r in small_radius_templates: # 小半径用模板绘制 template = small_radius_templates[r] half_size = r start_y, end_y = y - half_size, y + half_size + 1 start_x, end_x = x - half_size, x + half_size + 1 target_y1, target_y2 = max(0, start_y), min(H, end_y) target_x1, target_x2 = max(0, start_x), min(W, end_x) template_y1, template_y2 = max(0, -start_y), template.shape[0] - max(0, end_y - H) template_x1, template_x2 = max(0, -start_x), template.shape[1] - max(0, end_x - W) if target_y1 < target_y2 and target_x1 < target_x2: target_region = target_img[target_y1:target_y2, target_x1:target_x2] template_region = template[template_y1:template_y2, template_x1:template_x2] target_region[template_region == 1] = color else: # 大半径用OpenCV抗锯齿绘制 cv2.circle(target_img, (x, y), r, color, thickness=-1, lineType=cv2.LINE_AA)
三、额外优化建议
- 批量同参数圆:若存在大量半径、颜色相同的圆,可一次性计算所有圆的有效区域,用向量化操作赋值,比循环更快
- 多进程并行:将圆列表分成多个批次,用多进程并行绘制,进一步压缩耗时
- 预计算参数:提前计算所有模板的尺寸、半长等参数,避免循环内重复计算
内容的提问来源于stack exchange,提问作者gorschel
相关产品推荐
相关产品推荐

