Python实现火柴人的设计与实现
1.引言
火柴人(Stick Figure)是一种极简风格的图形,通常由简单的线段和圆圈组成,却能生动地表达人物的姿态和动作。火柴人不仅广泛应用于动画、漫画和涂鸦中,还可以作为图形学、人工智能等领域的教学和研究工具。本文旨在介绍如何使用Python实现火柴人的设计与绘制,通过编程的方式,让读者了解火柴人背后的基本原理和实现方法。
2.准备工作
在开始实现火柴人之前,你需要确保已经安装了Python环境,并且熟悉基本的Python编程知识。此外,为了绘制图形,我们将使用matplotlib
库,这是一个强大的绘图库,适用于生成各种静态、动态和交互式的图表。
你可以通过以下命令安装matplotlib
:
bash复制代码
pip install matplotlib
3.基础理论知识
火柴人的绘制主要依赖于几何图形的绘制和变换。具体来说,我们需要:
(1)定义关节:火柴人的关节包括头部、肩膀、肘部、手腕、臀部、膝盖和脚踝等。这些关节可以看作二维或三维空间中的点。
(2)绘制线段:根据关节的位置,绘制连接关节的线段,这些线段构成了火柴人的骨骼。
(3)添加圆形:在头部等关节处添加圆形,以表示关节。
(4)变换与动画:通过变换关节的位置,可以实现火柴人的动作和动画效果。
4.步骤详解
下面,我们将逐步介绍如何使用Python和matplotlib
绘制火柴人。
(1)导入库
首先,我们需要导入matplotlib
库中的pyplot
模块:
import matplotlib.pyplot as plt
import numpy as np
(2)定义关节位置
为了简单起见,我们先在二维平面上定义火柴人的关节位置。这里以一个简单的火柴人站立姿势为例:
# 定义关节位置
head = [0, 1]
torso = [0, 0]
left_shoulder = [-0.5, 0]
left_elbow = [-1, -0.5]
left_hand = [-1, -1]
right_shoulder = [0.5, 0]
right_elbow = [1, -0.5]
right_hand = [1, -1]
left_hip = [-0.5, -0.5]
left_knee = [-1, -1.5]
left_foot = [-1, -2]
right_hip = [0.5, -0.5]
right_knee = [1, -1.5]
right_foot = [1, -2]
# 将关节位置存储在一个字典中
joints = {
'head': head,
'torso': torso,
'left_shoulder': left_shoulder,
'left_elbow': left_elbow,
'left_hand': left_hand,
'right_shoulder': right_shoulder,
'right_elbow': right_elbow,
'right_hand': right_hand,
'left_hip': left_hip,
'left_knee': left_knee,
'left_foot': left_foot,
'right_hip': right_hip,
'right_knee': right_knee,
'right_foot': right_foot
}
(3)绘制火柴人
接下来,我们编写一个函数,根据关节位置绘制火柴人:
def draw_stick_figure(joints, ax):
# 绘制身体
body_parts = [
('torso', 'head'),
('torso', 'left_shoulder'), ('left_shoulder', 'left_elbow'), ('left_elbow', 'left_hand'),
('torso', 'right_shoulder'), ('right_shoulder', 'right_elbow'), ('right_elbow', 'right_hand'),
('torso', 'left_hip'), ('left_hip', 'left_knee'), ('left_knee', 'left_foot'),
('torso', 'right_hip'), ('right_hip', 'right_knee'), ('right_knee', 'right_foot')
]
for start, end in body_parts:
start_pos = np.array(joints[start])
end_pos = np.array(joints[end])
ax.plot([start_pos[0], end_pos[0]], [start_pos[1], end_pos[1]], 'k-')
# 绘制头部
circle = plt.Circle(joints['head'], 0.1, color='black', fill=True)
ax.add_patch(circle)
# 绘制手部(可选)
circle = plt.Circle(joints['left_hand'], 0.05, color='black', fill=True)
ax.add_patch(circle)
circle = plt.Circle(joints['right_hand'], 0.05, color='black', fill=True)
ax.add_patch(circle)
# 绘制脚部(可选)
circle = plt.Circle(joints['left_foot'], 0.05, color='black', fill=True)
ax.add_patch(circle)
circle = plt.Circle(joints['right_foot'], 0.05, color='black', fill=True)
ax.add_patch(circle)
(4)绘制并显示图形
最后,我们创建一个图形对象,调用绘制函数,并显示结果:
def main():
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.axis('off') # 关闭坐标轴
draw_stick_figure(joints, ax)
plt.show()
if __name__ == "__main__":
main()
5.常见问题解答
(1)火柴人看起来扭曲或比例不对:这通常是由于关节位置定义不合理或线段连接错误导致的。检查关节位置和连接顺序是否正确。
(2)图形显示不全:确保设置ax.set_aspect('equal')
,使得图形按等比例显示。
(3)如何添加动画效果:可以使用matplotlib
的FuncAnimation
类,通过不断更新关节位置来实现动画效果。
6.成果案例分享
通过上述步骤,你已经成功绘制了一个简单的火柴人。接下来,我们可以尝试更复杂的姿势和动画效果。例如,通过改变关节位置,实现火柴人的跳跃、行走等动作。
下面是一个简单的动画示例,展示火柴人从左到右移动的过程:
import matplotlib.animation as animation
def update_position(frame, joints):
# 这里我们简单地将火柴人向右移动
translation = 0.1 * frame
for key in joints.keys():
joints[key][0] += translation
return joints
def animate(frame):
global joints_anim
joints_anim = update_position(frame, joints_anim)
ax.clear()
ax.set_aspect('equal')
ax.axis('off')
draw_stick_figure(joints_anim, ax)
def main_animation():
fig, ax = plt.subplots()
global joints_anim
joints_anim = {key: value.copy() for key, value in joints.items()} # 复制初始关节位置
ani = animation.FuncAnimation(fig, animate, frames=100, interval=100)
plt.show()
if __name__ == "__main__":
main_animation()
7.案例代码示例
以下是完整的代码示例,包括所有步骤和注释:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
# 定义关节位置
joints = {
'head': [0, 1],
'torso': [0, 0],
'left_shoulder': [-0.5, 0],
'left_elbow': [-1, -0.5],
'left_hand': [-1, -1],
'right_shoulder': [0.5, 0],
'right_elbow': [1, -0.5],
'right_hand': [1, -1],
'left_hip': [-0.5, -0.5],
'left_knee': [-1, -1.5],
'left_foot': [-1, -2],
'right_hip': [0.5, -0.5],
'right_knee': [1, -1.5],
'right_foot': [1, -2]
}
# 将关节位置转换为numpy数组,以便进行数学运算
joints = {key: np.array(value) for key, value in joints.items()}
# 绘制火柴人的函数
def draw_stick_figure(joints, ax):
# 清除之前的绘图
ax.clear()
# 设置坐标轴的比例和限制
ax.set_aspect('equal')
ax.set_xlim(-2, 2)
ax.set_ylim(-2.5, 1.5)
# 定义身体部分和对应的颜色(可选)
body_parts = [
('torso', 'head', 'black'),
('torso', 'left_shoulder', 'black'), ('left_shoulder', 'left_elbow', 'black'), ('left_elbow', 'left_hand', 'black'),
('torso', 'right_shoulder', 'black'), ('right_shoulder', 'right_elbow', 'black'), ('right_elbow', 'right_hand', 'black'),
('torso', 'left_hip', 'black'), ('left_hip', 'left_knee', 'black'), ('left_knee', 'left_foot', 'black'),
('torso', 'right_hip', 'black'), ('right_hip', 'right_knee', 'black'), ('right_knee', 'right_foot', 'black')
]
# 绘制火柴人的各个部分
for part in body_parts:
start_joint, end_joint, color = part[0], part[1], part[2] if len(part) > 2 else 'black'
ax.plot([joints[start_joint][0], joints[end_joint][0]], [joints[start_joint][1], joints[end_joint][1]], color=color, linewidth=2)
# 显示网格(可选)
ax.grid(True)
# 创建图形和坐标轴
fig, ax = plt.subplots()
# 初始化函数(用于动画)
def init():
draw_stick_figure(joints, ax)
return [] # 返回空列表,因为我们没有需要更新的艺术家对象
# 动画更新函数
def update(frame):
# 这里可以添加使火柴人移动或改变姿势的逻辑
# 例如,简单地旋转手臂或腿
# 但为了简化,我们在这里不改变关节位置
draw_stick_figure(joints, ax)
return [] # 同样返回空列表
# 创建动画
ani = animation.FuncAnimation(fig, update, frames=100, init_func=init, blit=True, interval=100)
# 显示图形
plt.show()
请注意以下几点:
(1)我将关节位置转换为了numpy
数组,以便在需要时进行数学运算(虽然在这个简单的例子中并没有用到)。
(2)在draw_stick_figure
函数中,我添加了设置坐标轴比例和限制的代码,以及一个可选的网格显示。
(3)在body_parts
列表中,我添加了颜色参数,但在这个例子中,我默认使用了黑色。你可以根据需要更改颜色。
(4)在update
函数中,我没有改变关节位置,因此火柴人在动画中保持静止。你可以根据需要添加逻辑来改变火柴人的姿势或位置。
(5)我使用了FuncAnimation
来创建动画,并设置了100帧和每帧之间的间隔为100毫秒。你可以根据需要调整这些参数。
运行这段代码将显示一个包含静止火柴人的窗口,并且由于动画的设置,它会每隔100毫秒重新绘制一次(尽管看起来是静止的,因为关节位置没有改变,感兴趣的读者朋友可以尝试改变关节位置)。
Python实现火柴人的设计与实现的更多相关文章
- Python IAQ中文版 - Python中少有人回答的问题
Python中少有人回答的问题 The Python IAQ: Infrequently Answered Questions 1 Q: 什么是"少有人回答的问题(Infrequently ...
- Scratch编程:游泳的火柴人(四)
“ 上节课的内容全部掌握了吗?反复练习了没有,编程最好的学习方法就是练习.练习.再练习.一定要记得多动手.多动脑筋哦~~” 01 — 游戏介绍 这是一款简单的小游戏,实现了一个手绘的火柴人在水里游泳. ...
- python小练习1:设计这样一个函数,在桌面的文件夹上创建10个文本,以数字给它们命名。
python小练习1:设计这样一个函数,在桌面的文件夹上创建10个文本,以数字给它们命名. 使用for循环即可实现: for name in range(1,11): desktop_path='C: ...
- 利用 Python 尝试采用面向对象的设计方法计算图形面积及周长
利用 Python 尝试采用面向对象的设计方法.(1)设计一个基类 Shape:包含两个成员函数:def cal_area(): 计算并返回该图形的面积,保留两位小数:def cal_perimete ...
- 不老的新丁 Python何以让人着迷
Python是一门美丽的语言.它简单易学,跨平台,而且运转良好.达成了许多Java一直求索的技术目标.一言以蔽之就是:其他的语言是与时代同 步,而Python则是未雨绸缪,而且计划得颇为出色.当然,这 ...
- python函数的面向对象——面向对象设计
通过几个函数式编号演进,理解面向对象设计 def01.py dog1 = { 'name':'元昊', 'gender':'母', 'type':'藏獒' } dog2 = { 'name':'李李' ...
- python之接口与归一化设计
1接口 接口的概念: Java 语言中的接口很好的展现了接口的含义: IAnimal.java /* * Java的Interface很好的体现了我们前面分析的接口的特征: * 1)是一组功能的集合, ...
- Python基础-接口与归一化设计、抽象类、继承顺序、子类调用父类,多态与多态性
一.接口与归一化设计 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 由 ...
- python基础--接口与归一化设计、封装、异常、网络编程
1 接口与归一化设计 1.1 归一化概念: 归一化的好处: 1.归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大降低了使用者的使用难度. 2.归一化使得高层的外部 ...
- Python 番外 消息队列设计精要
消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的Active ...
随机推荐
- CCF A类会议 —— AAAI2022 论文审稿模板
======================================================= 前段时间为实验室负责审理AAAI 2022的会议稿件,感觉这个审稿模板还是不错的,这里保 ...
- 【转载】 NumPy之:数据类型对象dtype
原文地址: https://www.cnblogs.com/flydean/p/14720858.html ============================================== ...
- 用海豚调度器定时调度从Kafka到HDFS的kettle任务脚本
在实际项目中,从Kafka到HDFS的数据是每天自动生成一个文件,按日期区分.而且Kafka在不断生产数据,因此看看kettle是不是需要时刻运行?能不能按照每日自动生成数据文件? 为了测试实际项目中 ...
- Codeforces 929 div3 D
题目:D. Turtle Tenacity: Continual Mods 题目链接:https://codeforces.com/contest/1933/problem/D 算法:数论.贪心. 一 ...
- Structures, unions, enumerations, and bitfields in ARM C and C++
Structures, unions, enumerations, and bitfields in ARM C and C++ Non-Confidential ARM DUI0375E ARM ...
- Ubuntu 设置 SMB 服务
安装 Samba 包 sudo apt install samba samba-common 创建用于 SMB 共享的文件夹 sudo mkdir /usr/local/volumes # 新建用于共 ...
- vscode 安装历史版本
修改版本号为想要下载的版本即可 https://update.code.visualstudio.com/{版本}/win32-x64-archive/stable vscode 历史版本地址:Vis ...
- mysql where 字符串根据英文逗号分割为数组 并判断是否包含指定字符串
SELECT * FROM table_name where FIND_IN_SET('A',column_1) or FIND_IN_SET('B', column_2) table_name : ...
- Spark Dataframe 转 Json
import org.apache.spark.sql.DataFrame import org.apache.spark.sql.functions._ import org.apache.spar ...
- 注册中心Nacos集群搭建
一提到注册中心,大家往往想到Zookeeper.或者Eureka.今天我们看看阿里的一款配置中心+注册中心的中间件--Nacos.有了它以后,我们的项目中的配置就可以统一从Nacos中获取了,而且Sp ...