python绘制奥运吉祥物冰墩墩

本文最后更新于:2022年7月26日 下午

冰墩墩简介

冰墩墩(英文:Bing Dwen Dwen,汉语拼音:bīng dūn dūn),是2022年北京冬季奥运会的吉祥物。 将熊猫形象与富有超能量的冰晶外壳相结合,头部外壳造型取自冰雪运动头盔,装饰彩色光环,整体形象酷似航天员

2018年8月8日,北京冬奥会和冬残奥会吉祥物全球征集启动仪式举行。2019年9月17日晚,冰墩墩正式亮相 。

冰墩墩寓意创造非凡、探索未来,体现了追求卓越、引领时代,以及面向未来的无限可能。

python turtle绘图

主要用的是 Python 自带的 turtle

turtle库的基础命令介绍

(1)画布

画布是绘图区域,可以设置它的大小和初始位置

1
2
turtle.screensize(1000,600,'red')    大小的设置
turtle.setup(width=0.5,height=0.75) 初始位置

(2)画笔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(1)画笔运动的命令
turtle.forward(a) 向当前画笔方向移动a像素长度
turtle.backward(a) 向当前画笔相反方向移动a像素长度
turtle.right(a) 顺时针移动
aturtle.left(a) 逆时针移动
aturtle.pendown() 移动时绘制图形
turtle.goto(x,y) 将画笔移动到坐标为x,y的位置
turtle.penup() 移动时不绘制图形,提起笔
turtle.speed(a) 画笔绘制的速度范围
turtle.circle() 画图,半径为正,表示圆心在画笔的左边画圈

(2)画笔控制命令
turtle.pensize(width) 绘制图形的宽度
turtle.pencolor() 画笔的颜色
turtle.fillcolor(a) 绘制图形的填充颜色
turtle.color(a1,a2) 同时设置pencolor=a1,fillcolor=a2
turtle.filling() 返回当前是否在填充状态
turtle.begin_fill() 准备开始填充图形
turtle.end_fill() 填充完成
turtle.hideturtle() 隐藏箭头显示
turtle.showturtle() 显示箭头

(3)全局控制命令
turtle.clear() 清空turtle窗口,但是turtle的位置和状态不会改变
turtle.reset() 清空窗口,重置turtle状态为起始位置
turtle.undo() 撤销上一个turtle动作

硬“肝”不断调整曲线

turtle绘图小技巧

通过下面这个语句把你要参考的图先绘制在窗口中,然后再对照着进行绘制调整,就方便许多了。

1
turtle.bgpic('bg.png')

实现效果

image-20220209145209162

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
import turtle

turtle.title('画个冰墩墩--小马')

turtle.speed(10) # 速度

# 左手
turtle.penup()
turtle.goto(177, 112)
turtle.pencolor("lightgray")
turtle.pensize(3)
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(80)
turtle.circle(-45, 200)
turtle.circle(-300, 23)
turtle.end_fill()

# 左手内
turtle.penup()
turtle.goto(182, 95)
turtle.pencolor("black")
turtle.pensize(1)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.setheading(95)
turtle.pendown()
turtle.circle(-37, 160)
turtle.circle(-20, 50)
turtle.circle(-200, 30)
turtle.end_fill()
# 轮廓
# 头顶
turtle.penup()
turtle.goto(-73, 230)
turtle.pencolor("lightgray")
turtle.pensize(3)
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(20)
turtle.circle(-250, 35)
# 左耳
turtle.setheading(50)
turtle.circle(-42, 180)
# 左侧
turtle.setheading(-50)
turtle.circle(-190, 30)
turtle.circle(-320, 45)
# 左腿
turtle.circle(120, 30)
turtle.circle(200, 12)
turtle.circle(-18, 85)
turtle.circle(-180, 23)
turtle.circle(-20, 110)
turtle.circle(15, 115)
turtle.circle(100, 12)
# 右腿
turtle.circle(15, 120)
turtle.circle(-15, 110)
turtle.circle(-150, 30)
turtle.circle(-15, 70)
turtle.circle(-150, 10)
turtle.circle(200, 35)
turtle.circle(-150, 20)
# 右手
turtle.setheading(-120)
turtle.circle(50, 30)
turtle.circle(-35, 200)
turtle.circle(-300, 23)
# 右侧
turtle.setheading(86)
turtle.circle(-300, 26)
# 右耳
turtle.setheading(122)
turtle.circle(-53, 160)
turtle.end_fill()

# 右耳内
turtle.penup()
turtle.goto(-130, 180)
turtle.pencolor("black")
turtle.pensize(1)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(120)
turtle.circle(-28, 160)
turtle.setheading(210)
turtle.circle(150, 20)
turtle.end_fill()

# 左耳内
turtle.penup()
turtle.goto(90, 230)
turtle.setheading(40)
turtle.begin_fill()
turtle.pendown()
turtle.circle(-30, 170)
turtle.setheading(125)
turtle.circle(150, 23)
turtle.end_fill()

# 右手内
turtle.penup()
turtle.goto(-180, -55)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.setheading(-120)
turtle.pendown()
turtle.circle(50, 30)
turtle.circle(-27, 200)
turtle.circle(-300, 20)
turtle.setheading(-90)
turtle.circle(300, 14)
turtle.end_fill()

# 左腿内
turtle.penup()
turtle.goto(108, -168)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(-115)
turtle.circle(110, 15)
turtle.circle(200, 10)
turtle.circle(-18, 80)
turtle.circle(-180, 13)
turtle.circle(-20, 90)
turtle.circle(15, 60)
turtle.setheading(42)
turtle.circle(-200, 29)
turtle.end_fill()
# 右腿内
turtle.penup()
turtle.goto(-38, -210)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(-155)
turtle.circle(15, 100)
turtle.circle(-10, 110)
turtle.circle(-100, 30)
turtle.circle(-15, 65)
turtle.circle(-100, 10)
turtle.circle(200, 15)
turtle.setheading(-14)
turtle.circle(-200, 27)
turtle.end_fill()

# 右眼
# 眼圈
turtle.penup()
turtle.goto(-64, 120)
turtle.begin_fill()
turtle.pendown()
turtle.setheading(40)
turtle.circle(-35, 152)
turtle.circle(-100, 50)
turtle.circle(-35, 130)
turtle.circle(-100, 50)
turtle.end_fill()
# 眼珠
turtle.penup()
turtle.goto(-47, 55)
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(25, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(-45, 62)
turtle.pencolor("darkslategray")
turtle.fillcolor("darkslategray")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(19, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(-45, 68)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(10, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(-47, 86)
turtle.pencolor("white")
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(5, 360)
turtle.end_fill()

# 左眼
# 眼圈
turtle.penup()
turtle.goto(51, 82)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(120)
turtle.circle(-32, 152)
turtle.circle(-100, 55)
turtle.circle(-25, 120)
turtle.circle(-120, 45)
turtle.end_fill()
# 眼珠
turtle.penup()
turtle.goto(79, 60)
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(24, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(79, 64)
turtle.pencolor("darkslategray")
turtle.fillcolor("darkslategray")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(19, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(79, 70)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(10, 360)
turtle.end_fill()
turtle.penup()
turtle.goto(79, 88)
turtle.pencolor("white")
turtle.fillcolor("white")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(0)
turtle.circle(5, 360)
turtle.end_fill()

# 鼻子
turtle.penup()
turtle.goto(37, 80)
turtle.fillcolor("black")
turtle.begin_fill()
turtle.pendown()
turtle.circle(-8, 130)
turtle.circle(-22, 100)
turtle.circle(-8, 130)
turtle.end_fill()

# 嘴
turtle.penup()
turtle.goto(-15, 48)
turtle.setheading(-36)
turtle.begin_fill()
turtle.pendown()
turtle.circle(60, 70)
turtle.setheading(-132)
turtle.circle(-45, 100)
turtle.end_fill()

# 彩虹圈
turtle.penup()
turtle.goto(-135, 120)
turtle.pensize(5)
turtle.pencolor("cyan")
turtle.pendown()
turtle.setheading(60)
turtle.circle(-165, 150)
turtle.circle(-130, 78)
turtle.circle(-250, 30)
turtle.circle(-138, 105)
turtle.penup()
turtle.goto(-131, 116)
turtle.pencolor("slateblue")
turtle.pendown()
turtle.setheading(60)
turtle.circle(-160, 144)
turtle.circle(-120, 78)
turtle.circle(-242, 30)
turtle.circle(-135, 105)
turtle.penup()
turtle.goto(-127, 112)
turtle.pencolor("orangered")
turtle.pendown()
turtle.setheading(60)
turtle.circle(-155, 136)
turtle.circle(-116, 86)
turtle.circle(-220, 30)
turtle.circle(-134, 103)
turtle.penup()
turtle.goto(-123, 108)
turtle.pencolor("gold")
turtle.pendown()
turtle.setheading(60)
turtle.circle(-150, 136)
turtle.circle(-104, 86)
turtle.circle(-220, 30)
turtle.circle(-126, 102)
turtle.penup()
turtle.goto(-120, 104)
turtle.pencolor("greenyellow")
turtle.pendown()
turtle.setheading(60)
turtle.circle(-145, 136)
turtle.circle(-90, 83)
turtle.circle(-220, 30)
turtle.circle(-120, 100)
turtle.penup()

# 爱心
turtle.penup()
turtle.goto(220, 115)
turtle.pencolor("brown")
turtle.pensize(1)
turtle.fillcolor("brown")
turtle.begin_fill()
turtle.pendown()
turtle.setheading(36)
turtle.circle(-8, 180)
turtle.circle(-60, 24)
turtle.setheading(110)
turtle.circle(-60, 24)
turtle.circle(-8, 180)
turtle.end_fill()

# 五环
turtle.penup()
turtle.goto(-5, -170)
turtle.pendown()
turtle.pencolor("blue")
turtle.circle(6)
turtle.penup()
turtle.goto(10, -170)
turtle.pendown()
turtle.pencolor("black")
turtle.circle(6)
turtle.penup()
turtle.goto(25, -170)
turtle.pendown()
turtle.pencolor("brown")
turtle.circle(6)
turtle.penup()
turtle.goto(2, -175)
turtle.pendown()
turtle.pencolor("lightgoldenrod")
turtle.circle(6)
turtle.penup()
turtle.goto(16, -175)
turtle.pendown()
turtle.pencolor("green")
turtle.circle(6)
turtle.penup()

turtle.pencolor("black")
turtle.goto(-16, -160)
turtle.write("BEIJING 2022", font=('Arial', 10, 'bold italic'))
turtle.hideturtle()

turtle.done()

opencv+turtle自动绘图

先看效果

image-20220209151707506

实现过程

turtle是python的一个很好玩的自动绘图工具。然而,用它来画一幅画需要提供大量的坐标点。有的人为了用它画出一幅好看的画不惜去手工计算图片线稿的描点的位置。心疼一秒。
其实我们完全可以用计算机图像识别来自动获取图片边缘的位置坐标,比如Opencv。
我们先直接上python的opencv一个基本案例。

记得先安装opencv-python库

1
2
3
import cv2
img = cv2.imread("bingdundun.png")#读取一张图片
cv2.imshow("窗口标题",img)#在一个窗口显示图片

cv2.imread()是读取一个图像文件,然后将图像的像素信息转化成一个numpy矩阵,并返回
cv2.imshow()则是读取一个numpy矩阵信息,将其作为像素信息在新窗口中打印出来。
ok,读取图片工作完成了,那我们现在来获取图片的边缘信息

1
point=cv2.Canny(img, 000, 200)

这是边缘检测函数,将img图像的边缘像素信息作为numpy矩阵返回,里面的0和200这个参数是阈值范围参数,可自行调节。
虽然得到了边缘位置的信息,但这个矩阵信息却是显示的图像的矩阵的旋转矩阵。因此我们还需要对所得矩阵进行旋转,否则可能会得到倒过来的图像。

1
2
import numpy
point=numpy.rot90(black,k=3)

numpy.rot90()这个函数是矩阵顺时针旋转90度的函数,k代表旋转的次数,经过我的测试,要旋转3次才矫正(也就是逆时针一次)。
得到绘图点的像素信息后,我们开始用turtle进行绘图

1
2
3
4
5
6
7
8
9
import turtle
for y in range(0,len(point)):
for x in range(0,len(point[y])):
if point[y][x]!=0:
turtle.penup()
turtle.goto(y,x)
turtle.pendown()
turtle.goto(y,x)
turtle.penup()

这里就是直接判断x,y坐标下绘图点矩阵的像素信息是否为0,因为绘图点矩阵是通过canny边缘识别得到的,故除了边缘意外的位置像素值都为0.这样就能描绘出一张图片的线稿了
此外还有其他参数可以调节,比如缩放图像尺寸,笔的大小,绘图的中心位置,绘图速度等等。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import cv2
import turtle
import numpy
img = cv2.imread("i.png")
cv2.imshow("biaoti",img)
black=cv2.Canny(img, 000, 200)
height, width=black.shape[:2]
point = cv2.resize(black, (int(width/4), int(height/4)), interpolation=cv2.INTER_CUBIC)
point=numpy.rot90(point,k=3)
turtle.setup(600,600)
x0=int(len(point[0])/2)
y0=int(len(point)/2)
turtle.pensize(3)

turtle.speed(1000)
for y in range(0,len(point),2):
for x in range(0,len(point[y]),2):
if point[y][x]!=0:
print(y,x)
turtle.penup()
turtle.goto(y-y0,x-x0)
turtle.pendown()
turtle.goto(y-y0,x-x0)
turtle.penup()
while 1:
pass

使用opencv找轮廓

实现效果

image-20220209152121194

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding:utf-8 -*-
# __author__ = "mayuke"

# 导入模块
import turtle
import cv2 as cv
import numpy as np

# 读取图片,并设置相关参数
src = cv.imread("img.jpg")
# print(src.shape)
cv.imshow('s1', src)
width = src.shape[1]
hight = src.shape[0]
print(width, hight)
turtle.setup(width + 15, hight + 15)
turtle.bgcolor(0, 0, 0)
turtle.pencolor(1, 1, 1)

# 用一个函数将图片左上角设置成坐标原点(0,0)
def y(x, y):
x = x - 1 / 2 * width
y = -(y - 1 / 2 * hight)
return x, y

# 将图片转成灰度图并进行二值化
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, image = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)

# 使用opencv找轮廓
counters, re = cv.findContours(image, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
print('轮廓个数:', len(counters))

# 遍历轮廓进行画图
for i, con in enumerate(counters):

area = cv.contourArea(con)

con = np.reshape(con, (con.shape[0], 2))

turtle.goto(y(con[0, 0], con[0, 1]))
turtle.pendown()

biao_x1 = np.argmin(con[:, 0])
x1 = con[biao_x1, 0]
y1 = con[biao_x1, 1]
# print('x1,y1=',x1,y1)

biao_x2 = np.argmax(con[:, 0])
x2 = con[biao_x2, 0]
y2 = con[biao_x2, 1]
# print('x2,y2=', x2, y2)

biao_y3 = np.argmin(con[:, 1])
x3 = con[biao_y3, 0]
y3 = con[biao_y3, 1]
# print('x3,y3=', x3, y3)
# 下边坐标
biao_y4 = np.argmin(con[:, 1])
x4 = con[biao_y4, 0]
y4 = con[biao_y4, 1]
# print('x4,y4=', x4, y4)

x1 = x1
# right
x2 = x2
# up
y3 = y3
# bottom
y4 = y4
print('x1,y1=', x1, y1)
print('x2,y2=', x2, y2)
print('x3,y3=', x3, y3)
print('x4,y4=', x4, y4)
if x1 < width and x2 >= 0 and y3 < hight and y4 >= 0:
a1 = image[y1, x1] / 255

a2 = image[y2, x2] / 255

a3 = image[y3, x3] / 255

a4 = image[y4, x4] / 255
else:
a1 = a2 = a3 = a4 = 0

a = a1 + a2 + a3 + a4

turtle.begin_fill()

if a > 5:
turtle.fillcolor(1, 1, 1)
elif a <= 5:
turtle.fillcolor(0, 0, 0)
# 画图
for shu, c in enumerate(con):
turtle.goto(y(c[0], c[1]))
turtle.goto(y(con[0, 0], con[0, 1]))
turtle.end_fill()
turtle.penup()

turtle.mainloop()

参考资料

Python绘制冬奥吉祥物“冰墩墩”_turtle_goto_Crossin (sohu.com)

(55条消息) opencv+turtle自动绘图_林雪飞的博客-CSDN博客_opencv 线稿

(55条消息) python 用turtle自动画图_qq 1735375343的博客-CSDN博客_python自动绘图