我将为您创建一个完整的儿童绘本插画生成器项目。
项目结构
children_book_illustrator/ ├── main.py # 主程序入口 ├── config.py # 配置文件 ├── illustration_generator.py # 插画生成核心模块 ├── coloring_module.py # 上色功能模块 ├── style_manager.py # 风格管理模块 ├── utils.py # 工具函数 ├── requirements.txt # 依赖包列表 ├── README.md # 使用说明 └── knowledge_cards.md # 核心知识点卡片
- requirements.txt
Pillow==10.0.0 numpy==1.24.3 matplotlib==3.7.2 opencv-python==4.8.1.78 scikit-learn==1.3.0
- config.py
""" 配置文件 - 定义插画生成的默认参数和样式配置 """
绘本主题类型
THEME_TYPES = { "童话": { "style": "fantasy", "colors": ["#FFB6C1", "#87CEEB", "#98FB98", "#DDA0DD", "#F0E68C"], "elements": ["castle", "dragon", "princess", "unicorn", "magic_wand"], "line_style": "soft" }, "科普": { "style": "realistic", "colors": ["#4169E1", "#32CD32", "#FF6347", "#9370DB", "#20B2AA"], "elements": ["animal", "plant", "planet", "microscope", "rocket"], "line_style": "precise" }, "成长": { "style": "warm", "colors": ["#FFA07A", "#20B2AA", "#778899", "#90EE90", "#DDA0DD"], "elements": ["child", "family", "school", "friends", "dream"], "line_style": "gentle" } }
画布尺寸配置
CANVAS_SIZES = { "small": (400, 300), "medium": (800, 600), "large": (1200, 900) }
默认参数
DEFAULT_CONFIG = { "canvas_size": "medium", "theme": "童话", "has_color": False, "line_thickness": 2, "complexity": "medium" # simple, medium, complex }
- utils.py
""" 工具函数模块 - 提供通用的辅助功能 """
import random from PIL import Image, ImageDraw import numpy as np
def create_canvas(width, height, background_color="white"): """创建画布""" return Image.new('RGB', (width, height), background_color)
def get_random_position(canvas_width, canvas_height, margin=50): """获取随机位置,避免太靠近边缘""" x = random.randint(margin, canvas_width - margin) y = random.randint(margin, canvas_height - margin) return x, y
def interpolate_points(points, num_interpolations=5): """在关键点之间插值,使线条更平滑""" if len(points) < 2: return points
interpolated = []
for i in range(len(points) - 1):
interpolated.append(points[i])
# 在当前点和下一点之间插入点
current = np.array(points[i])
next_point = np.array(points[i + 1])
for j in range(1, num_interpolations):
t = j / (num_interpolations + 1)
interpolated_point = tuple(current * (1 - t) + next_point * t)
interpolated.append(interpolated_point)
interpolated.append(points[-1])
return interpolated
def apply_gaussian_blur(image, sigma=1.0): """应用高斯模糊效果""" from PIL import ImageFilter return image.filter(ImageFilter.GaussianBlur(radius=sigma))
- style_manager.py
""" 风格管理模块 - 处理不同主题的视觉风格 """
from .config import THEME_TYPES import random
class StyleManager: def init(self): self.themes = THEME_TYPES
def get_theme_config(self, theme_name):
"""获取指定主题的配置"""
return self.themes.get(theme_name, self.themes["童话"])
def get_random_element(self, theme_name):
"""获取主题相关的随机元素"""
theme_config = self.get_theme_config(theme_name)
return random.choice(theme_config["elements"])
def get_color_palette(self, theme_name, num_colors=5):
"""获取主题配色方案"""
theme_config = self.get_theme_config(theme_name)
colors = theme_config["colors"]
return random.sample(colors, min(num_colors, len(colors)))
def get_line_style_params(self, theme_name):
"""获取线条样式参数"""
theme_config = self.get_theme_config(theme_name)
line_style = theme_config["line_style"]
style_params = {
"soft": {"thickness": 2, "smoothness": 0.8},
"precise": {"thickness": 1, "smoothness": 0.3},
"gentle": {"thickness": 1.5, "smoothness": 0.6}
}
return style_params.get(line_style, style_params["soft"])
5. illustration_generator.py
""" 插画生成核心模块 - 负责生成线稿和上色 """
import random from PIL import Image, ImageDraw import numpy as np from .utils import create_canvas, get_random_position, interpolate_points from .style_manager import StyleManager
class IllustrationGenerator: def init(self): self.style_manager = StyleManager() self.current_theme = "童话"
def set_theme(self, theme):
"""设置当前主题"""
if theme in ["童话", "科普", "成长"]:
self.current_theme = theme
else:
raise ValueError("不支持的主题类型")
def generate_silhouette(self, element_type, position, size, canvas_size):
"""生成元素的轮廓点"""
width, height = canvas_size
x, y = position
# 根据不同元素类型生成不同的轮廓
if element_type == "castle":
return self._generate_castle_outline(x, y, size)
elif element_type == "dragon":
return self._generate_dragon_outline(x, y, size)
elif element_type == "princess":
return self._generate_princess_outline(x, y, size)
elif element_type == "unicorn":
return self._generate_unicorn_outline(x, y, size)
elif element_type == "magic_wand":
return self._generate_magic_wand_outline(x, y, size)
elif element_type == "animal":
return self._generate_animal_outline(x, y, size)
elif element_type == "tree":
return self._generate_tree_outline(x, y, size)
elif element_type == "house":
return self._generate_house_outline(x, y, size)
else:
# 默认圆形轮廓
return self._generate_circle_outline(x, y, size)
def _generate_circle_outline(self, x, y, size):
"""生成圆形轮廓"""
points = []
num_points = 20
for i in range(num_points):
angle = 2 * np.pi * i / num_points
px = x + size * np.cos(angle)
py = y + size * np.sin(angle)
points.append((px, py))
return points
def _generate_tree_outline(self, x, y, size):
"""生成树的轮廓(树干+树冠)"""
points = []
# 树干
trunk_width = size // 3
trunk_height = size
trunk_left = x - trunk_width // 2
trunk_top = y - trunk_height // 2
# 树干矩形
points.extend([
(trunk_left, trunk_top),
(trunk_left + trunk_width, trunk_top),
(trunk_left + trunk_width, trunk_top + trunk_height),
(trunk_left, trunk_top + trunk_height),
(trunk_left, trunk_top)
])
# 树冠(圆形)
crown_radius = size // 2
for i in range(15):
angle = 2 * np.pi * i / 15
px = x + crown_radius * np.cos(angle)
py = y - trunk_height // 4 + crown_radius * np.sin(angle)
points.append((px, py))
return points
def _generate_house_outline(self, x, y, size):
"""生成房子的轮廓"""
points = []
half_size = size // 2
# 房子主体
house_left = x - half_size
house_top = y - half_size // 2
house_right = x + half_size
house_bottom = y + half_size // 2
# 矩形主体
points.extend([
(house_left, house_top),
(house_right, house_top),
(house_right, house_bottom),
(house_left, house_bottom),
(house_left, house_top)
])
# 屋顶(三角形)
roof_height = size // 4
points.extend([
(house_left, house_top),
(x, house_top - roof_height),
(house_right, house_top),
(house_left, house_top)
])
# 门
door_width = size // 6
door_left = x - door_width // 2
door_top = house_bottom - size // 6
points.extend([
(door_left, door_top),
(door_left + door_width, door_top),
(door_left + door_width, house_bottom),
(door_left, house_bottom),
(door_left, door_top)
])
return points
def _generate_animal_outline(self, x, y, size):
"""生成简单动物轮廓(类似小猫)"""
points = []
# 身体(椭圆)
body_width = size
body_height = size * 0.7
for i in range(20):
angle = 2 * np.pi * i / 20
px = x + (body_width/2) * np.cos(angle)
py = y + (body_height/2) * np.sin(angle)
points.append((px, py))
# 头部
head_size = size * 0.6
for i in range(15):
angle = 2 * np.pi * i / 15
px = x + head_size * np.cos(angle) * 0.8
py = y - body_height/2 + head_size * np.sin(angle) * 0.6
points.append((px, py))
return points
def draw_illustration(self, elements_count=3, complexity="medium"):
"""绘制完整插画"""
# 获取画布尺寸
canvas_size = (800, 600)
canvas = create_canvas(*canvas_size, "white")
draw = ImageDraw.Draw(canvas)
# 获取主题配置
theme_config = self.style_manager.get_theme_config(self.current_theme)
line_params = self.style_manager.get_line_style_params(self.current_theme)
# 生成多个元素
for _ in range(elements_count):
# 获取随机元素和位置
element = self.style_manager.get_random_element(self.current_theme)
position = get_random_position(*canvas_size, margin=100)
size = random.randint(50, 150)
# 生成轮廓
outline_points = self.generate_silhouette(element, position, size, canvas_size)
# 平滑处理
if complexity in ["medium", "complex"]:
outline_points = interpolate_points(outline_points, num_interpolations=3)
# 绘制轮廓
if len(outline_points) > 1:
draw.line(outline_points + [outline_points[0]],
fill="black",
width=int(line_params["thickness"]))
# 添加装饰性背景元素
self._add_decorative_elements(draw, canvas_size, theme_config)
return canvas
def _add_decorative_elements(self, draw, canvas_size, theme_config):
"""添加装饰性背景元素"""
width, height = canvas_size
# 添加一些星星或花朵作为装饰
for _ in range(5):
x = random.randint(20, width - 20)
y = random.randint(20, height - 20)
# 简单的星形装饰
star_points = []
for i in range(5):
angle = 2 * np.pi * i / 5
outer_x = x + 8 * np.cos(angle)
outer_y = y + 8 * np.sin(angle)
star_points.append((outer_x, outer_y))
inner_angle = 2 * np.pi * (i + 0.5) / 5
inner_x = x + 4 * np.cos(inner_angle)
inner_y = y + 4 * np.sin(inner_angle)
star_points.append((inner_x, inner_y))
draw.polygon(star_points, fill="lightgray", outline="gray")
6. coloring_module.py
""" 上色功能模块 - 为线稿添加颜色 """
from PIL import Image, ImageDraw import random from .style_manager import StyleManager
class ColoringModule: def init(self): self.style_manager = StyleManager()
def colorize_illustration(self, illustration, theme=None):
"""为插画添加颜色"""
if theme is None:
theme = "童话"
colored_image = illustration.copy()
draw = ImageDraw.Draw(colored_image)
width, height = colored_image.size
# 获取主题配色
colors = self.style_manager.get_color_palette(theme, num_colors=8)
# 为每个封闭区域填充颜色
self._fill_random_regions(draw, width, height, colors)
return colored_image
def _fill_random_regions(self, draw, width, height, colors):
"""填充随机区域"""
# 创建几个大的填充区域
num_regions = random.randint(3, 6)
for _ in range(num_regions):
# 随机形状:圆形、椭圆形或多边形
shape_type = random.choice(["circle", "ellipse", "polygon"])
color = random.choice(colors)
if shape_type == "circle":
x = random.randint(50, width - 50)
y = random.randint(50, height - 50)
radius = random.randint(30, 80)
draw.ellipse([x-radius, y-radius, x+radius, y+radius],
fill=color, outline="black", width=2)
elif shape_type == "ellipse":
x1 = random.randint(50, width - 150)
y1 = random.randint(50, height - 100)
x2 = x1 + random.randint(60, 120)
y2 = y1 + random.randint(40, 80)
draw.ellipse([x1, y1, x2, y2],
fill=color, outline="black", width=2)
elif shape_type == "polygon":
# 创建多边形
num_points = random.randint(5, 8)
points = []
center_x = random.randint(100, width - 100)
center_y = random.randint(100, height - 100)
for i in range(num_points):
angle = 2 * 3.14159 * i / num_points
radius = random.randint(40, 70)
x = center_x + radius * (0.5 + 0.5 * random.random()) * np.cos(angle)
y = center_y + radius * (0.5 + 0.5 * random.random()) * np.sin(angle)
points.append((x, y))
if len(points) >= 3:
draw.polygon(points, fill=color, outline="black", width=2)
def add_gradient_background(self, image, color1, color2):
"""添加渐变背景"""
# 这里可以实现渐变背景效果
# 简化版本:直接返回原图
return image
7. main.py
""" 主程序入口 - 提供用户界面和功能调用 """
import tkinter as tk from tkinter import ttk, filedialog, messagebox from PIL import Image, ImageTk import os from .illustration_generator import IllustrationGenerator from .coloring_module import ColoringModule from .config import DEFAULT_CONFIG, CANVAS_SIZES
class ChildrenBookIllustratorGUI: def init(self): self.root = tk.Tk() self.root.title("儿童绘本插画生成器") self.root.geometry("1000x700")
self.generator = IllustrationGenerator()
self.coloring_module = ColoringModule()
self.current_image = None
self.setup_ui()
def setup_ui(self):
"""设置用户界面"""
# 主框架
main_frame = ttk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 左侧控制面板
control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding=10)
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
# 主题选择
ttk.Label(control_frame, text="绘本主题:").pack(anchor=tk.W)
self.theme_var = tk.StringVar(value="童话")
theme_combo = ttk.Combobox(control_frame, textvariable=self.theme_var,
values=["童话", "科普", "成长"], state="readonly")
theme_combo.pack(fill=tk.X, pady=(0, 10))
# 元素数量
ttk.Label(control_frame, text="元素数量:").pack(anchor=tk.W)
self.elements_var = tk.IntVar(value=3)
elements_scale = ttk.Scale(control_frame, from_=1, to=6,
variable=self.elements_var, orient=tk.HORIZONTAL)
elements_scale.pack(fill=tk.X, pady=(0, 10))
# 复杂度选择
ttk.Label(control_frame, text="复杂度:").pack(anchor=tk.W)
self.complexity_var = tk.StringVar(value="medium")
complexity_combo = ttk.Combobox(control_frame, textvariable=self.complexity_var,
values=["simple", "medium", "complex"], state="readonly")
complexity_combo.pack(fill=tk.X, pady=(0, 10))
# 按钮
ttk.Button(control_frame, text="生成线稿",
command=self.generate_sketch).pack(fill=tk.X, pady=2)
ttk.Button(control_frame, text="添加颜色",
command=self.add_colors).pack(fill=tk.X, pady=2)
ttk.Button(control_frame, text="保存图片",
command=self.save_image).pack(fill=tk.X, pady=2)
ttk.Button(control_frame, text="清空画布",
command=self.clear_canvas).pack(fill=tk.X, pady=2)
# 右侧显示区域
display_frame = ttk.LabelFrame(main_frame, text="插画预览", padding=10)
display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
# 创建画布用于显示图片
self.canvas = tk.Canvas(display_frame, bg="white", width=600, height=500)
self.canvas.pack(expand=True)
# 状态栏
self.status_var = tk.StringVar(value="准备就绪")
status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def generate_sketch(self):
"""生成线稿"""
try:
# 更新主题
self.generator.set_theme(self.theme_var.get())
# 生成插画
elements_count = int(self.elements_var.get())
complexity = self.complexity_var.get()
self.status_var.set("正在生成线稿...")
self.root.update()
self.current_image = self.generator.draw_illustration(
elements_count=elements_count,
complexity=complexity
)
self.display_image(self.current_image)
self.status_var.set("线稿生成完成")
except Exception as e:
messagebox.showerror("错误", f"生成线稿时出错: {str(e)}")
self.status_var.set("生成失败")
def add_colors(self):
"""为插画添加颜色"""
if self.current_image is None:
messagebox.showwarning("警告", "请先生成线稿")
return
try:
self.status_var.set("正在添加颜色...")
self.root.update()
colored_image = self.coloring_module.colorize_illustration(
self.current_image, self.theme_var.get()
)
self.current_image = colored_image
self.display_image(self.current_image)
self.status_var.set("上色完成")
except Exception as e:
messagebox.showerror("错误", f"上色时出错: {str(e)}")
self.status_var.set("上色失败")
def display_image(self, image):
"""在界面上显示图片"""
# 调整图片大小以适应显示区域
display_size = (580, 480)
display_image = image.resize(display_size, Image.Resampling.LANCZOS)
# 转换为PhotoImage
self.photo = ImageTk.PhotoImage(display_image)
# 清除画布并显示新图片
self.canvas.delete("all")
self.canvas.create_image(290, 240, image=self.photo)
def save_image(self):
"""保存图片"""
if self.current_image is None:
messagebox.showwarning("警告", "没有可保存的图片")
return
try:
filename = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg"), ("All files", "*.*")]
)
if filename:
self.current_image.save(filename)
self.status_var.set(f"图片已保存到: {filename}")
messagebox.showinfo("成功", "图片保存成功!")
except Exception as e:
messagebox.showerror("错误", f"保存图片时出错: {str(e)}")
def clear_canvas(self):
"""清空画布"""
self.canvas.delete("all")
self.current_image = None
self.status_var.set("画布已清空")
def run(self):
"""运行应用程序"""
self.root.mainloop()
def main(): """主函数""" app = ChildrenBookIllustratorGUI() app.run()
if name == "main": main()
- README.md
儿童绘本插画生成器
一个基于Python的儿童绘本插画自动生成工具,支持童话、科普、成长三种主题,能够快速生成线稿并提供上色功能。
功能特点
- 🎨 多主题支持:童话、科普、成长三种绘本主题
- ✏️ 智能线稿生成:根据主题自动生成相关元素轮廓
- 🌈 一键上色:为线稿添加符合主题的色彩搭配
- 🖥️ 直观界面:友好的图形用户界面,操作简单
- 💾 便捷导出:支持多种格式图片保存
安装说明
环境要求
- Python 3.7+
- pip 包管理器
安装步骤
- 克隆或下载项目文件
- 安装依赖包:
bash
pip install -r requirements.txt
- 运行程序:
bash
python main.py
使用指南
基本操作
- 选择主题:在下拉菜单中选择绘本主题(童话/科普/成长)
- 调整参数:
- 元素数量:控制插画中元素的数量(1-6个)
- 复杂度:选择插画的复杂程度(简单/中等/复杂)
- 生成线稿:点击"生成线稿"按钮创建黑白线稿
- 添加颜色:点击"添加颜色"按钮为插画上色
- 保存作品:点击"保存图片"按钮将作品保存到本地
主题特色
- 童话主题:包含城堡、龙、公主等奇幻元素,配色温馨梦幻
- 科普主题:包含动物、植物、星球等科学元素,配色清新自然
- 成长主题:包含家庭、学校、朋友等生活元素,配色温暖治愈
技术架构
- GUI框架:Tkinter
- 图像处理:Pillow (PIL)
- 数值计算:NumPy
- 算法设计:几何图形生成、颜色搭配算法
项目结构
children_book_illustrator/
├── main.py # 主程序入口
├── config.py # 配置文件
├── illustration_generator.py # 插画生成核心
├── coloring_module.py # 上色功能
├── style_manager.py # 风格管理
├── utils.py # 工具函数
└── requirements.txt # 依赖包
扩展开发
添加新的主题
- 在
config.py的THEME_TYPES中添加新主题配置 - 在
illustration_generator.py中添加对应的元素生成方法 - 为新主题设计专属的颜色搭配
自定义元素
可以通过修改 generate_silhouette 方法来添加自定义的图形元素,支持各种几何形状和复杂图案。
注意事项
- 首次运行可能需要较长时间加载依赖库
- 生成的图片分辨率适中,适合绘本制作参考
- 建议定期保存作品,避免意外丢失
许可证
MIT License
联系方式
如有问题或建议,欢迎提交Issue或联系开发者。
- knowledge_cards.md
核心知识点卡片
🎨 艺术设计基础
卡片1:色彩理论基础
知识点:色彩三要素与情感表达
- 色相(Hue):色彩的基本属性,决定颜色的种类
- 饱和度(Saturation):色彩的纯度,影响视觉冲击力
- 明度(Value):色彩的明暗程度,营造氛围感
- 应用:童话主题使用高饱和度暖色调营造梦幻感;科普主题采用中低饱和度冷色调体现科学性
卡片2:构图原理
知识点:视觉重心与平衡法则
- 三分法:将画面分为九宫格,重要元素放在交叉点上
- 对称与均衡:创造稳定感或动态感
- 留白艺术:给观者想象空间,突出主体
- 实践:插画生成器中通过随机位置算法实现自然的构图分布
💻 编程技术要点
卡片3:面向对象设计
知识点:模块化架构设计
- 单一职责原则:每个类只负责一个功能模块
- 封装性:隐藏实现细节,提供清晰接口
- 继承与多态:提高代码复用性和扩展性
- 实例:StyleManager、IllustrationGenerator等类的设计体现了良好的封装
卡片4:图形学基础
知识点:矢量图形生成算法
- 贝塞尔曲线:创建平滑的曲线路径
- 多边形填充:扫描线算法和边界填充算法
- 坐标变换:平移、旋转、缩放变换矩阵
- 应用:通过数学计算生成各种几何图形的轮廓点
卡片5:GUI开发模式
知识点:事件驱动编程
- 回调函数:响应用户交互的核心机制
- MVC模式:模型-视图-控制器的分离设计
- 状态管理:跟踪应用程序当前状态
- 实践:Tkinter的事件循环和组件绑定机制
🚀 创新设计思维
卡片6:参数化设计
知识点:通过参数控制创意输出
- 变量控制:用数字参数控制视觉元素
- 组合爆炸:少量参数产生大量变化
- 用户参与:让用户成为创意的共同创造者
- 优势:提高创作效率,保持风格一致性
卡片7:算法美学
知识点:用数学创造美感
- 随机性与规律性:在秩序中寻找变化
- 分形几何:自相似性的美学应用
- 黄金比例:自然界中的美学法则
- 实现:通过随机数生成器和几何算法创造有机的视觉效果
卡片8:用户体验设计
知识点:以用户为中心的设计理念
- 易用性原则:简单直观的操作流程
- 反馈机制:及时的状态提示和操作确认
- 容错设计:优雅处理异常情况
- 评估:通过用户测试和迭代改进产品
📊 项目管理知识
卡片9:敏捷开发流程
知识点:快速迭代的开发方法
- MVP思维:先做最小可行产品验证想法
- 持续集成:频繁的小规模更新
- 用户反馈:早期和持续的测试
- 应用:从简单线稿生成逐步扩展到完整功能
卡片10:开源协作规范
知识点:代码质量和文档标准
- PEP8规范:Python代码风格指南
- 文档注释:清晰的API文档和使用说明
- 版本控制:Git的分支管理和提交规范
- 重要性:保证代码的可维护性和可扩展性
🎯 创业实践启示
卡片11:MVP产品开发
知识点:最小可行性产品的构建策略
- 核心价值:解决用户最痛的痛点
- 快速验证:用最简单的方式测试市场反应
- 迭代优化:基于反馈持续改进产品
- 案例:从基础的几何图形生成开始,逐步增加主题和复杂度
卡片12:用户需求分析
知识点:深入理解目标用户
- 用户画像:明确目标用户的特征和需求
- 使用场景:理解用户在什么情况下使用产品
- 痛点识别:发现现有解决方案的不足
- 洞察:绘本作者需要快速出稿工具,但缺乏绘画技能
卡片13:技术商业化路径
知识点:从技术到商业的转化思路
- 差异化定位:找到独特的市场切入点
- 价值包装:将技术能力转化为用户价值
- 商业模式:考虑免费增值、订阅等多种盈利方式
- 扩展方向:从工具向平台发展,构建创作者社区
💡 学习建议:将这些知识点与实际项目结合,通过动手实践加深理解,培养跨学科的综合思维能力。
这个完整的儿童绘本插画生成器项目包含了:
- 模块化设计:清晰的代码结构,易于维护和扩展
- 功能完整:支持主题选择、线稿生成、上色、保存等功能
- 用户友好:提供图形界面,操作简单直观
- 教学价值:详细的注释和文档,适合学习参考
- 扩展性:预留了添加新主题和功能的接口
项目可以帮助绘本作者快速生成创意草图,提高创作效率,同时也展示了如何将艺术设计与编程技术相结合的创新实践。 关注我,有更多实用程序等着你!