两种颜色去除算法的对比
easterling

最近在工作中遇到需要删除图片中某一颜色及其类似颜色的功能,函数接受颜色、颜色范围两个主要参数,我按照gpt的指引写出了下列算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def remove_color_range(image_path:str, color:list, width:int):
lower_bound = np.array([max(x - width,0) for x in color]) # 需要去除的颜色的下界
upper_bound = np.array([min(x + width,255) for x in color]) # 需要去除的颜色的上界

img = Image.open(image_path).convert('RGBA')

# 将图片转换为NumPy数组
img_array = np.array(img)

# 创建一个布尔数组,标记需要去除的像素
mask = np.all((img_array >= lower_bound) & (img_array <= upper_bound), axis=-1)

# 将需要去除的像素设置为白色(或其他你想要的颜色)
img_array[mask] = [0, 0, 0, 0]

# 将NumPy数组转换回PIL图像
new_img = Image.fromarray(img_array)

return new_img

而导师给了我另一种实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def color_within_tolerance(color, target, tolerance):
"""检查颜色是否在目标颜色的容差范围内"""
return all(abs(c - t) <= tolerance for c, t in zip(color, target))

def remove_color(input_image_path, output_image_path, target_color, tolerance):
image = Image.open(input_image_path).convert("RGBA")
datas = image.getdata()

new_data = []
for item in datas:
# 检查当前像素是否在容差范围内
if color_within_tolerance(item[:3], target_color, tolerance):
# 将匹配的颜色替换为透明
new_data.append((255, 255, 255, 0))
else:
new_data.append(item)

image.putdata(new_data)
image.save(output_image_path, "PNG")

导师的代码额外加入了输出,我使用同一张图片进行测试,两者的效果完全一致。

那么两者的效率是否相同呢,我在我的函数中也加上保存图片的环节进行测试得出的时间之比为: 0.496: 3.702,换另一张图测试,时间比为 0.958:10.208,看来我这边确实更快,

原理看上去也比较简单,后者是通过逐个对比像素来确定是否要替换对应点的,而前者是通过np包将图片转成矩阵后使用np.all(函数进行处理,np.all() 是 NumPy 中的一个非常有用的函数,它用于检查数组中所有元素是否都为 True。而当 axis=-1 时,表示沿着最后一个轴(即宽度轴)进行操作,(理解起来可能有点困难,可以看作对矩阵降维,两行三列的数组,降维的方式有两种,一种是横向取与,一种是纵向取与,得到的分别是一行两列和一行三列的bool数组,数组中的值表示这一行或这一列是否都符合条件),也就是img_array判断矩阵的最小维度是否符合条件,对比的是[229 229 229 255]是否不大于[249 249 249 255]中的每一个对应元素,[229 229 229 255]是否不小于[209 209 209 235]中的每一个对应元素,如均符合,则此像素置为true,np.all最终得到的是一个布尔数组,再经过img_array[mask] = [0, 0, 0, 0]将原图的对应像素置为透明即可。

借助于numpy,其中的筛选和修改似乎都是并行计算,因此效率高得多。

 Comments
Comment plugin failed to load
Loading comment plugin