Python实现图像转带网格与符号的刺绣风格海报图技术问询
刺绣辅助工具开发指引需求
我正在开发一款基于tkinter的工具,帮母亲完成刺绣项目,同时提升自己的Python技能。工具需要实现以下自动化流程:
- 加载图像
- 按用户自定义数量进行颜色量化
- 按自定义像素块大小(如16x16px)进行像素化
- 生成对应块大小的网格叠加层
- 根据颜色RGB值生成唯一符号并放置于网格中
目前已用ttk搭建GUI,通过PIL实现了量化与基于百分比的像素化,但需将像素化改为基于像素块大小的方式,同时寻求网格叠加与符号放置的技术方向,不需求完整解决方案,仅需指引。
一、基于像素块大小的像素化改造
把当前按百分比缩小的逻辑改成固定块大小处理,步骤如下:
- 从输入框
e2获取用户设置的块大小,转换为整数block_size - 计算缩小后的尺寸:
new_w = w // block_size、new_h = h // block_size(用整数除法直接取整,无需四舍五入) - 缩小图像时使用
Image.NEAREST采样模式,避免颜色模糊(刺绣需要清晰色块):down_sampled = im.resize((new_w, new_h), resample=Image.NEAREST) - 放大回原尺寸时同样用
Image.NEAREST,保证每个块保持纯色:up_sampled = down_sampled.resize((w, h), resample=Image.NEAREST)
二、网格叠加层实现方向
两种简单可行的实现思路:
- 直接在PIL图像上绘制网格:
用ImageDraw.Draw创建绘图对象,每隔block_size像素绘制一条水平/垂直线,选择与图像对比度强烈的颜色(如黑色),线条宽度设为1即可,绘制完成后直接保存图像。 - 在tkinter画布上叠加网格:
将处理后的图像显示在tkinter的Canvas组件中,使用canvas.create_line()绘制网格线,坐标对应块大小的间隔。这种方式支持后续交互,比如点击网格块查看颜色信息。
三、颜色对应符号放置方向
- 建立颜色-符号映射表:
用im.getcolors()提取量化后图像的所有唯一颜色,为每个颜色分配一个专属符号(字母、数字、特殊符号均可),用字典存储:color_symbol = {(r, g, b): 'A', (r2, g2, b2): 'B', ...} - 符号放置实现:
- 用PIL实现:使用
ImageDraw.Draw.text(),在每个像素块的中心位置绘制对应符号,字体大小设为block_size//2左右,颜色选择与块颜色对比度强烈的(如浅色块用黑色字)。 - 用tkinter Canvas实现:使用
canvas.create_text(),在每个块的中心位置放置文本,直接通过映射表获取对应符号。
- 用PIL实现:使用
当前代码框架
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
相关产品推荐
相关产品推荐

