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

OpenCV中是否有便捷方法在圆形内适配绘制文本?

我明白你的痛点——直接把圆心坐标传给cv2.putText()确实没法让文本完美适配圆形,因为OpenCV的文本绘制锚点是基线的左下角,不是文本中心。这里有几个优雅的解决方案,分单行和多行文本两种情况来说:

单行文本:让文本中心与圆心重合

核心思路是先计算文本的实际尺寸,再反向推导合适的绘制坐标,确保文本中心和圆心完全对齐:

import cv2
import numpy as np

# 定义参数
FONT = cv2.FONT_HERSHEY_SIMPLEX
FONT_SCALE = 1.5
TEXT_COLOUR = (255, 0, 0)
TEXT_THICKNESS = 2
CIRCLE_RADIUS = 100
cX, cY = 300, 300  # 圆心坐标
text = "Hello OpenCV"

# 创建空白画布(或者读取你的frame)
frame = np.zeros((600, 600, 3), dtype=np.uint8)

# 计算文本的宽度、高度,以及基线偏移量
(text_width, text_height), baseline = cv2.getTextSize(
    text, FONT, FONT_SCALE, TEXT_THICKNESS
)

# 计算文本绘制的起始坐标:让文本中心与圆心重合
draw_x = int(cX - text_width / 2)
# 这里的y坐标需要考虑文本的垂直中心,因为putText的锚点是基线
draw_y = int(cY + text_height / 2)

# 绘制圆形和文本
cv2.circle(frame, (cX, cY), CIRCLE_RADIUS, (0, 255, 0), 2)
cv2.putText(
    frame, text, (draw_x, draw_y),
    FONT, FONT_SCALE, TEXT_COLOUR, TEXT_THICKNESS, cv2.LINE_AA
)

# 查看结果
cv2.imshow("Text in Circle", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键说明:

  • cv2.getTextSize()是核心:它返回文本的实际像素宽度、高度,以及基线到文本底部的偏移量,这是精准计算坐标的基础。
  • 调整后的draw_x让文本水平居中,draw_y确保文本垂直中心与圆心对齐,避免了文本偏移出圆形的问题。
多行文本:自动换行适配圆形范围

如果文本过长,单行会超出圆形边界,这时候需要自动拆分文本为多行,确保每行宽度不超过圆形直径,同时整体垂直居中:

def put_text_in_circle(
    frame, text, cX, cY, radius, font, font_scale, text_colour, thickness
):
    # 圆形内允许的最大文本宽度(直径)
    max_line_width = 2 * radius
    line_spacing = 5  # 行间距
    
    # 拆分文本为单词,再组合成符合宽度的行
    words = text.split()
    lines = []
    current_line = []
    current_width = 0
    space_width = cv2.getTextSize(" ", font, font_scale, thickness)[0][0]

    for word in words:
        word_width = cv2.getTextSize(word, font, font_scale, thickness)[0][0]
        # 计算当前行加入单词后的总宽度(含空格)
        proposed_width = current_width + word_width + (space_width if current_line else 0)
        if proposed_width <= max_line_width:
            current_line.append(word)
            current_width = proposed_width
        else:
            lines.append(" ".join(current_line))
            current_line = [word]
            current_width = word_width
    # 加入最后一行
    if current_line:
        lines.append(" ".join(current_line))
    
    # 计算所有行的总高度,用于垂直居中
    total_height = 0
    line_heights = []
    for line in lines:
        _, line_h = cv2.getTextSize(line, font, font_scale, thickness)[0]
        line_heights.append(line_h)
        total_height += line_h + line_spacing
    
    # 第一行的起始y坐标:让整个文本块垂直居中
    current_y = cY - total_height // 2 + line_heights[0] // 2

    # 逐行绘制文本
    for i, line in enumerate(lines):
        line_width, line_h = cv2.getTextSize(line, font, font_scale, thickness)[0]
        draw_x = cX - line_width // 2
        cv2.putText(
            frame, line, (draw_x, current_y),
            font, font_scale, text_colour, thickness, cv2.LINE_AA
        )
        # 更新下一行的y坐标
        current_y += line_h + line_spacing

# 使用示例
frame = np.zeros((600, 600, 3), dtype=np.uint8)
cv2.circle(frame, (cX, cY), CIRCLE_RADIUS, (0, 255, 0), 2)
long_text = "This is a long text that needs to be wrapped inside the circle in OpenCV"
put_text_in_circle(
    frame, long_text, cX, cY, CIRCLE_RADIUS,
    FONT, FONT_SCALE, TEXT_COLOUR, TEXT_THICKNESS
)

cv2.imshow("Wrapped Text in Circle", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键说明:

  • 先按单词拆分文本,逐行判断是否超出圆形宽度,自动换行。
  • 计算所有行的总高度后,让整个文本块垂直居中于圆形,保证视觉上的和谐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:36:16