- Published on
使用 python 提取图片中文字的颜色
- Authors
- Name
- Sean
- @him50653330
背景
书接上文,我们已经实现了识别图片中的文字并且将文字涂抹掉。接下来,我们需要将文字翻译成目标语言,并重新绘制到图片上。
这里我们先不讲如何进行翻译,下次我们来介绍怎么翻译博大精深的中文。我们先讲一下将文字重新绘制时候碰到的一个问题:文字的颜色。
我们希望重新绘制回去的文字能够保留原来的颜色,这样看起来整张图片仍然能够原来的风格。
提取颜色
首先,我们首先使用的方案是提取识别区域的主色。但是这个方案并不奏效。
我们可以看到,识别的区域中有大面积的背景颜色,我们使用主色的方式提取颜色,很容易会提取到背景颜色。
我们需要的是文字区域内的颜色,所以我们需要一个更加精细的方案。
首先,我想到的方案就是识别出文字的实际区域,然后在这个区域内提取颜色。
第一步,我尝试了使用 canny 边缘检测算法,计算出文字的边缘。因为我们已经将识别的区域限制在了文字区域内,所以这个图像的「环境」相对是简单的,边缘检测能够很好的识别出文字的边缘。
接下来,就是要将这区域内的颜色提取出来,这下就难道我了,我没有专业的图像处理知识,我只能使用一些非专业的手段来解决这个问题。
我的第一个想法是将识别出来的区域向中心缩小,然后提取缩小后的区域上的点的颜色,这样理论上就能提取出文字的颜色。
但是这只是理想的情况,中文字的特点是笔画繁多,这样的缩小会碰到各种情况,边界不闭合、超出边界、不同的大小区域等等,提取出来的颜色并不是我们想要的。
最后,我们分别在文字区域的 x,y 两个方向的 1/4、1/2 和 3/4 处提取边缘点左右上下 2-5 像素(随机取两个点)的颜色
对于这些颜色,我们继续对其进行处理找出最接近的颜色,我们将每个颜色与所有的颜色计算欧几里得距离,找到这个颜色的最小距离,如果这个最小距离大于阈值(防止同色),我们将这个颜色加入到颜色列表中。
由于这些颜色是我们通过有限的抽样提取的边缘附近的颜色,有效屏蔽了背景的干扰,通过最小距离筛选我们筛选出相同颜色最多的色值作为最后的结果。
def get_colors(colors, cropped_image):
try:
colors_lab = np.array([np.array([[color[::-1]]], dtype=np.float32) / 255.0 for color in colors])
# 将图像转换为NumPy数组,并只处理一半宽度
image_np = np.array(cropped_image, dtype=np.float32)[:,:cropped_image.size[0]//2] / 255.0
# 初始化一个空列表来存储符合条件的颜色
word_colors = []
# 对于图像中的每个像素
for pixel_lab in image_np.reshape(-1, image_np.shape[-1]):
# 计算与颜色列表中每种颜色的距离
distances = np.linalg.norm(colors_lab - pixel_lab, axis=2)
# 找到最小距离
min_distance = np.min(distances)
# 检查最小距离是否超过阈值
if min_distance > color_distance_threhold:
word_colors.append(tuple((pixel_lab * 255.0).astype(np.uint8).tolist()))
return word_colors
except Exception as e:
print(e)
return None
nearest_color = Counter(colors).most_common(1)[0][0]
效果
预告
下次介绍如何使用 RAG + LLM 实现翻译