如何用Python实现书法字母的线条粗细自适应点填充效果
书法字母转动态点填充效果实现方案
核心思路
利用距离变换获取文字线条的粗细信息,以此控制点的大小,再通过网格采样绘制连贯的点集,替代原线条。
步骤1:图像预处理(提取文字+获取粗细信息)
先把图像转为灰度并二值化,再通过距离变换计算每个文字像素到边缘的距离(距离值直接对应线条粗细):
import cv2 import numpy as np # 读取图像 img = cv2.imread("your_calligraphy_img.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化(反相,让文字区域为白色) _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 距离变换:计算每个文字像素到最近边缘的距离,值越大线条越粗 distance_map = cv2.distanceTransform(binary, cv2.DIST_L2, 5)
步骤2:映射距离值为点半径
把距离值归一化到你需要的点大小范围,比如最小1像素,最大8像素:
min_radius = 1 max_radius = 8 # 归一化距离值到半径区间 radius_map = cv2.normalize(distance_map, None, min_radius, max_radius, cv2.NORM_MINMAX)
步骤3:采样并绘制点填充效果
用网格采样遍历文字区域,按对应半径绘制圆形,保证点的连贯性:
# 创建空白画布 result = np.zeros_like(img) # 采样步长:控制点的密度,步长越小点越密 sample_step = 3 # 遍历采样点 for y in range(0, binary.shape[0], sample_step): for x in range(0, binary.shape[1], sample_step): # 只在文字区域绘制点 if binary[y, x] == 255: radius = int(radius_map[y, x]) cv2.circle(result, (x, y), radius, (255, 255, 255), -1) # 保存或显示结果 cv2.imwrite("dot_fill_result.jpg", result) cv2.imshow("Result", result) cv2.waitKey(0)
优化技巧
- 如果原图像有噪点,预处理时加高斯模糊:
gray = cv2.GaussianBlur(gray, (3, 3), 0),避免噪点生成多余的点。 - 调整
sample_step控制点的密度:步长为2-4时,点的连贯性较好,同时不会过于密集。 - 若想让点的颜色和原书法颜色一致,可把绘制颜色改为原图像对应位置的颜色:
color = img[y, x]。
内容的提问来源于stack exchange,提问作者CepBep
相关产品推荐
相关产品推荐

