You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现图像转带网格与符号的刺绣风格海报图技术问询

刺绣辅助工具开发指引需求

我正在开发一款基于tkinter的工具,帮母亲完成刺绣项目,同时提升自己的Python技能。工具需要实现以下自动化流程:

  • 加载图像
  • 按用户自定义数量进行颜色量化
  • 按自定义像素块大小(如16x16px)进行像素化
  • 生成对应块大小的网格叠加层
  • 根据颜色RGB值生成唯一符号并放置于网格中

目前已用ttk搭建GUI,通过PIL实现了量化与基于百分比的像素化,但需将像素化改为基于像素块大小的方式,同时寻求网格叠加与符号放置的技术方向,不需求完整解决方案,仅需指引。


一、基于像素块大小的像素化改造

把当前按百分比缩小的逻辑改成固定块大小处理,步骤如下:

  1. 从输入框e2获取用户设置的块大小,转换为整数block_size
  2. 计算缩小后的尺寸:new_w = w // block_size、new_h = h // block_size(用整数除法直接取整,无需四舍五入)
  3. 缩小图像时使用Image.NEAREST采样模式,避免颜色模糊(刺绣需要清晰色块):
    down_sampled = im.resize((new_w, new_h), resample=Image.NEAREST)
    
  4. 放大回原尺寸时同样用Image.NEAREST,保证每个块保持纯色:
    up_sampled = down_sampled.resize((w, h), resample=Image.NEAREST)
    

二、网格叠加层实现方向

两种简单可行的实现思路:

  • 直接在PIL图像上绘制网格:
    用ImageDraw.Draw创建绘图对象,每隔block_size像素绘制一条水平/垂直线,选择与图像对比度强烈的颜色(如黑色),线条宽度设为1即可,绘制完成后直接保存图像。
  • 在tkinter画布上叠加网格:
    将处理后的图像显示在tkinter的Canvas组件中,使用canvas.create_line()绘制网格线,坐标对应块大小的间隔。这种方式支持后续交互,比如点击网格块查看颜色信息。

三、颜色对应符号放置方向

  1. 建立颜色-符号映射表:
    用im.getcolors()提取量化后图像的所有唯一颜色,为每个颜色分配一个专属符号(字母、数字、特殊符号均可),用字典存储:
    color_symbol = {(r, g, b): 'A', (r2, g2, b2): 'B', ...}
    
  2. 符号放置实现:
    • 用PIL实现:使用ImageDraw.Draw.text(),在每个像素块的中心位置绘制对应符号,字体大小设为block_size//2左右,颜色选择与块颜色对比度强烈的(如浅色块用黑色字)。
    • 用tkinter Canvas实现:使用canvas.create_text(),在每个块的中心位置放置文本,直接通过映射表获取对应符号。

当前代码框架

import tkinter as tk
from tkinter import ttk

from PIL import Image

import numpy as np
import os

# root window
root = tk.Tk()
root.geometry('300x200')
root.title('Embroidery Generator')

# Load image button (This is how I would like the tool to operate)
loadLabel= tk.Label(
    root,
    text='Source image',
)

loadLabel.grid(
    row=0,
    column=0,
    sticky='w',
)

loadButton= ttk.Button(
    root,
    text='Load...',
)

loadButton.grid(
    row=0,
    column=1,
    sticky='w',
)

# Max Colors Entry
maxColorsLabel= tk.Label(
    root,
    text='Max. colors'
)

maxColorsLabel.grid(
    row=1,
    column=0,
    sticky='w',
)

e1= tk.Entry(
    root,

)

e1.grid(
    row=1,
    column=1,
    sticky='w',
)

# Grid size Entry
gridLabel= tk.Label(
    root,
    text='Grid size'
)

gridLabel.grid(
    row=2,
    column=0,
    sticky='w',
)

e2= tk.Entry(
    root,
)

e2.grid(
    row=2,
    column=1,
    sticky='w',
)

# Quantization button to reduce max color (will become user input)
def quantize():
    im = Image.open(os.path.expanduser("~/Downloads/surf.png")).convert('RGB')
    im = im.quantize(4, dither=None)
    im.save(os.path.expanduser("~/Downloads/surf_quantized.png"))
    im.show()

quantize_button = ttk.Button(
    root,
    text='1.Quantize',
    command=quantize
)

quantize_button.grid(
    row=4,
    column=0,
    sticky='w',
)

# Pixelate button (will also become user input)
def pixelate():
    im = Image.open(os.path.expanduser("~/Downloads/surf_quantized.png"))
#find its width & height
    w,h = im.size
#find NEW dimensions from user-defined number (in percentages now. Want to transform this in 'blocks' based on pixels)
    new_w = w * 0.05
    new_h = h * 0.05
#round to nearest whole number and convert from float to int
    new_w = np.round(new_w)
    new_w = int(new_w)
    new_h = np.round(new_h)
    new_h = int(new_h)
#downsample image to these new dimensions
    down_sampled = im.resize((new_w, new_h))
#upsample back to original size (using "4" to signify bicubic)
    up_sampled = down_sampled.resize((w, h), resample = 4)
#save the image
    up_sampled.save(os.path.expanduser("~/Downloads/surf_pixalated.png"))
    up_sampled.show()

pixelate_button = ttk.Button(
    root,
    text='2.Pixelate!',
    command=pixelate
)

pixelate_button.grid(
    row=5,
    column=0,
    sticky='w',
)

# exit button
exit= ttk.Button(
    root,
    text="Exit",
    command=lambda: root.quit()
)

exit.grid(
    row=6,
    column=0,
    sticky='w',
)

root.mainloop()

内容的提问来源于stack exchange,提问作者Ricked

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:24:55