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
相关产品推荐
相关产品推荐

