首页 > 解决方案 > 有没有办法优化这个字典搜索?

问题描述

我有一些代码可以打开图像并使用 ANSI 转义序列将图像的表示打印到终端。它获取图像缩小版本中的每个像素,并使用与其匹配的颜色打印一个字符。然而,并非所有终端都支持 RGB 输出,所以我想实现其他颜色模式,例如 4 位。我使用包含 ANSI 代码和它们产生的 RGB 值的字典查找表来做到这一点:{(r, g, b) : code, .... 然后我根据欧几里德距离打印最接近像素颜色的值。

from PIL import Image, ImageOps
from math import sqrt, inf

def match_colour_to_table(table, colour):
    best_colour = None
    best_diff = inf
    
    for table_colour in table.keys():
        # Calculate the distance between the two colours
        delta = (c - t for c, t in zip(colour, table_colour))
        diff = sqrt(sum((p ** 2 for p in delta)))
        
        if diff < best_diff:
            best_colour = table_colour
            best_diff = diff

    return table[selected_colour]

def term_pixel_4bit(colour):
    colour_table = {
        (0,   0,   0)   : 40,
        (255, 0,   0)   : 41,
        (0,   255, 0)   : 42,
        (255, 255, 0)   : 43,
        (0,   0,   255) : 44,
        (255, 0,   255) : 45,
        (0,   255, 255) : 46,
        (255, 255, 255) : 47,
    }

    code = match_colour_to_table(colour_table, colour)
        
    return f"\033[;{code}m \033[0m"

def term_pixel_256(colour):
    match_colour_to_table(TABLE_256, colour)

    return f"\033[48;5;{code}m ";

def print_image(image, size):
    width, height = size
    image = image.resize(size, resample=1).convert("RGB")
    
    # Print each row of characters
    for y in range(height):            
        row = [term_pixel_256(image.getpixel((x, y)))
               for x in range(width)]
        
        # Reset to avoid trailing colours
        row.append("\033[0m")
        printf("".join(row))

这种方法对于 4 位颜色效果很好,但对于 256 色效果则差很多。我将https://jonasjacek.github.io/colors/data.json上的 json 数据转换为字典。

TABLE_256 = {
    (0, 0, 0) : 0, (128, 0, 0) : 1, (0, 128, 0) : 2, 
    ... 
    (228, 228, 228) : 254, (238, 238, 238) : 255
}

它确实产生了一个漂亮的结果,但可以理解的是它需要一段时间来计算。我确信有一种更快的方法可以做到这一点,但我不完全确定从哪里开始。任何帮助将非常感激。

以防万一,这里是调用站点:

path  = os.path.join(os.path.dirname(__file__), "")
image = Image.open(path + sys.argv[1])
print_image(image, (100, 50))

标签: pythonoptimizationterminalpython-imaging-librarylookup

解决方案


您可以尝试将functools.lru_cache应用于term_pixel_4bit

import functools

@functools.lru_cache
def term_pixel_256(colour):
    match_colour_to_table(TABLE_256, colour)

    return f"\033[48;5;{code}m ";


推荐阅读