下面部分为本人初窥python的世界有感所作。
在学python之前,我总觉得这个东西很玄乎,而且认为网上传的很邪门:几行画出一个函数图,几十行做出一个人物形象,几十行写出一个小游戏。当时只觉得时夸大其词了。后来慢慢学习python,虽然知道了它可以用好多库,但也并没有觉得有什么。直到这次学长给我机会让我做一些东西,我才真正了解到它如何去使用,才真正发现它的乐趣,因此开启了新世界的大门,非常感谢学长!!!
在学习python的初期,思维总被束缚,总觉得去实现读取网页连接、打开文件读取每个文件、修改图片信息等等这些很难实现,结果发现这些。。。其实都在库里面实现好了,只需要去调用它即可。直到我认识到了这一点,我才开始走进这个python的世界。(不愧为超级语言)
在学习pyhton中,陆陆续续也了解到了其他的知识,例如Linux,服务器,网站等等知识。对我来说,这些东西有着很大的吸引力。学习这些东西非常有趣,好玩,在休闲时间做做这些,挺享受,但是也挺虐心(库中的各种函数不会使用)。唯一遗憾的是,到了现在才了解到这些东西。
以后继续努力把~~~
turtle库,也叫海龟库。是入门级的图形绘制函数库。
turtle的原(wan)理(fa):
想象一只小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,在窗体正中心,在画布上游走,它走过的轨迹就形成了绘制的图形。它由程序控制,当然,我们可以改变它的颜色,宽度,速度,行动轨迹等等。
画笔(画笔的属性,颜色、画线的宽度等)
1) turtle.pensize():设置画笔的宽度;
2) turtle.pencolor():没有参数传入,返回当前画笔颜色,传入参数设置画笔颜色,可以是字符串如”green”, “red”,也可以是RGB 3元组。例如turtle.pencolor(“red”),画笔就会改成红色。
3) turtle.speed (speed):设置画笔移动速度,画笔绘制的速度范围[0,10]整数,数字越大越快。turtle.speed(10)为最快。(画笔最快,而不是你最快 – .- 手动狗头)
操纵海龟绘图有着许多的命令,这些命令可以划分为3种:
一种为运动命令,一种为画笔控制命令,还有一种是全局控制命令。
(1) 画笔运动命令
命令 | 说明 |
---|---|
turtle.forward(distance) | 向当前画笔方向移动distance像素长度 |
turtle.backward(distance) | 向当前画笔相反方向移动distance像素长度 |
turtle.right(degree) | 顺时针移动degree° |
turtle.left(degree) | 逆时针移动degree° |
turtle.pendown() | 移动时绘制图形,缺省时也为绘制 |
turtle.goto(x,y) | 将画笔移动到坐标为x,y的位置 |
turtle.penup() | 提起笔移动,不绘制图形,用于另起一个地方绘制 |
turtle.circle() | 画圆,半径为正(负),表示圆心在画笔的左边(右边)画圆 |
setx( ) | 将当前x轴移动到指定位置 |
sety( ) | 将当前y轴移动到指定位置 |
setheading(angle) | 设置当前朝向为angle角度 |
home() | 设置当前画笔位置为原点,朝向东。 |
dot(r) | 绘制一个指定直径和颜色的圆点 |
(2) 画笔控制命令
命令 | 说明 |
---|---|
turtle.fillcolor(colorstring) | 绘制图形的填充颜色 |
turtle.color(color1, color2) | 同时设置pencolor=color1, fillcolor=color2 |
turtle.filling() | 返回当前是否在填充状态 |
turtle.begin_fill() | 准备开始填充图形 |
turtle.end_fill() | 填充完成 |
turtle.hideturtle() | 隐藏画笔的turtle形状 |
turtle.showturtle() | 显示画笔的turtle形状 |
(3) 全局控制命令
命令 | 说明 |
---|---|
turtle.clear() | 清空turtle窗口,但是乌龟的位置和状态不会改变 |
turtle.reset() | 清空窗口,重置turtle状态为起始状态 |
turtle.undo() | 撤销上一个turtle动作 |
turtle.isvisible() | 返回当前turtle是否可见 |
stamp() | 复制当前图形 |
turtle.write(s [,font=(“font-name”,font_size,”font_type”)]) | 写文本,s为文本内容,font是字体的参数,分别为字体名称,大小和类型;font为可选项,font参数也是可选项 |
好了,现在我们可以举个实例来运用这些操作了:
简单时钟 Python import turtle from datetime import * # 抬起画笔,向前运动一段距离放下 def Skip(step): turtle.penup() turtle.forward(step) turtle.pendown() def mkHand(name, length): # 注册Turtle形状,建立表针Turtle turtle.reset() Skip(-length * 0.1) # 开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。 turtle.begin_poly() turtle.forward(length * 1.1) # 停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。 turtle.end_poly() # 返回最后记录的多边形。 handForm = turtle.get_poly() turtle.register_shape(name, handForm) def Init(): global secHand, minHand, hurHand, printer # 重置Turtle指向北 turtle.mode("logo") # 建立三个表针Turtle并初始化 mkHand("secHand", 135) mkHand("minHand", 125) mkHand("hurHand", 90) secHand = turtle.Turtle() secHand.shape("secHand") minHand = turtle.Turtle() minHand.shape("minHand") hurHand = turtle.Turtle() hurHand.shape("hurHand") for hand in secHand, minHand, hurHand: hand.shapesize(1, 1, 3) hand.speed(0) # 建立输出文字Turtle printer = turtle.Turtle() # 隐藏画笔的turtle形状 printer.hideturtle() printer.penup() def SetupClock(radius): # 建立表的外框 turtle.reset() turtle.pensize(7) for i in range(60): Skip(radius) if i % 5 == 0: turtle.forward(20) Skip(-radius - 20) Skip(radius + 20) if i == 0: turtle.write(int(12), align="center", font=("Courier", 14, "bold")) elif i == 30: Skip(25) turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-25) elif (i == 25 or i == 35): Skip(20) turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-20) else: turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-radius - 20) else: turtle.dot(5) Skip(-radius) turtle.right(6) def Week(t): week = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"] return week[t.weekday()] def Date(t): y = t.year m = t.month d = t.day return "%s %d%d" % (y, m, d) def Tick(): # 绘制表针的动态显示 t = datetime.today() second = t.second + t.microsecond * 0.000001 minute = t.minute + second / 60.0 hour = t.hour + minute / 60.0 secHand.setheading(6 * second) minHand.setheading(6 * minute) hurHand.setheading(30 * hour) turtle.tracer(False) printer.forward(65) printer.write(Week(t), align="center", font=("Courier", 14, "bold")) printer.back(130) printer.write(Date(t), align="center", font=("Courier", 14, "bold")) printer.h0ome() turtle.tracer(True) # 100ms后继续调用tick turtle.ontimer(Tick, 100) def main(): # 打开/关闭龟动画,并为更新图纸设置延迟。 turtle.tracer(False) Init() SetupClock(160) turtle.tracer(True) Tick() turtle.mainloop() if __name__ == "__main__": main() 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 import turtle from datetime import * # 抬起画笔,向前运动一段距离放下 def Skip(step): turtle.penup() turtle.forward(step) turtle.pendown() def mkHand(name, length): # 注册Turtle形状,建立表针Turtle turtle.reset() Skip(-length * 0.1) # 开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。 turtle.begin_poly() turtle.forward(length * 1.1) # 停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。 turtle.end_poly() # 返回最后记录的多边形。 handForm = turtle.get_poly() turtle.register_shape(name, handForm) def Init(): global secHand, minHand, hurHand, printer # 重置Turtle指向北 turtle.mode("logo") # 建立三个表针Turtle并初始化 mkHand("secHand", 135) mkHand("minHand", 125) mkHand("hurHand", 90) secHand = turtle.Turtle() secHand.shape("secHand") minHand = turtle.Turtle() minHand.shape("minHand") hurHand = turtle.Turtle() hurHand.shape("hurHand") for hand in secHand, minHand, hurHand: hand.shapesize(1, 1, 3) hand.speed(0) # 建立输出文字Turtle printer = turtle.Turtle() # 隐藏画笔的turtle形状 printer.hideturtle() printer.penup() def SetupClock(radius): # 建立表的外框 turtle.reset() turtle.pensize(7) for i in range(60): Skip(radius) if i % 5 == 0: turtle.forward(20) Skip(-radius - 20) Skip(radius + 20) if i == 0: turtle.write(int(12), align="center", font=("Courier", 14, "bold")) elif i == 30: Skip(25) turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-25) elif (i == 25 or i == 35): Skip(20) turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-20) else: turtle.write(int(i/5), align="center", font=("Courier", 14, "bold")) Skip(-radius - 20) else: turtle.dot(5) Skip(-radius) turtle.right(6) def Week(t): week = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"] return week[t.weekday()] def Date(t): y = t.year m = t.month d = t.day return "%s %d%d" % (y, m, d) def Tick(): # 绘制表针的动态显示 t = datetime.today() second = t.second + t.microsecond * 0.000001 minute = t.minute + second / 60.0 hour = t.hour + minute / 60.0 secHand.setheading(6 * second) minHand.setheading(6 * minute) hurHand.setheading(30 * hour) turtle.tracer(False) printer.forward(65) printer.write(Week(t), align="center", font=("Courier", 14, "bold")) printer.back(130) printer.write(Date(t), align="center", font=("Courier", 14, "bold")) printer.h0ome() turtle.tracer(True) # 100ms后继续调用tick turtle.ontimer(Tick, 100) def main(): # 打开/关闭龟动画,并为更新图纸设置延迟。 turtle.tracer(False) Init() SetupClock(160) turtle.tracer(True) Tick() turtle.mainloop() if __name__ == "__main__": main()
这段代码运行后,会画出一个简单的时钟,实时的表示现在的时间。
然而,运行出来的钟表是黑色的。。。很不酷,,,
所以我们只要在绘制图形时设置画笔的颜色就行了,那么我们应该怎么告诉计算机我们想用什么颜色的呢?
这里我们就了解到了RGB色彩模式。
RGB色彩模式是由三种颜色,也就是R(red),G(green),B(blue)构成的万物色。它的每个取值范围为0-255整数或者0-1小数,三种颜色不同的取值就构成了不同的颜色,具体的某个颜色可以网上搜出来表来对照。ex:
蓝色(blue): (0,0,255)or (0,0,1)
粉色(pink):(255,192,203) or (1,0.75,0.8)
于是我们有三种变换颜色的方法:pencolor(“blue”) pencolor(0,0,255) pencolor(0,0,1)
这三种方法都是把颜色变为蓝色,一般来说,记住颜色的英文名称为最好。
然而,我们发现这还不够,turtle虽然功能很齐全,但是在绘制函数图等某种具体的需求上显得有些乏力,所以我们渴望有新的东西可以满足我们的需求。
于是——–matplotlib库与NumPy 库脚踏七彩祥云从西边归来了。
在这里为什么将这两个库合起来介绍呢?是因为:matplotlib库是一个数据可视化库,顾名思义,就是将数据以表的形式呈现出来。而NumPy是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。所以它们两个结合在一起就可以根据我们的需求来绘制相应的图形。例如绘制我们最熟悉的sin,cos这些三角函数图像。
代码如下:
Python
import numpy as np import matplotlib.pyplot as plt # 设置x,y轴的数值 x1 = np.linspace(0, 4*np.pi, 100) y1 = np.sin(x1) y2 = np.cos(x1) # 画图(x轴,y轴,给所绘制的曲线的名字,画线颜色,画线宽度) plt.plot(x1, y1, label="$sin(x)$", color="blue", linewidth=2) plt.plot(x1, y2, label="$cos(x)$", color="red", linewidth=2) # X和Y坐标轴 plt.xlabel("x") plt.ylabel("sin(x) and cos(x)") # 图表的标题 plt.title("sin and cos") # Y轴的范围 plt.ylim(-1.5, 1.5) plt.xlim(0,4*np.pi) # 显示图示 plt.legend() # 显示图 plt.show()
12345678910111213141516171819202122232425262728 | import numpy as npimport matplotlib.pyplot as plt # 设置x,y轴的数值x1 = np.linspace(0, 4*np.pi, 100)y1 = np.sin(x1)y2 = np.cos(x1) # 画图(x轴,y轴,给所绘制的曲线的名字,画线颜色,画线宽度)plt.plot(x1, y1, label="$sin(x)$", color="blue", linewidth=2)plt.plot(x1, y2, label="$cos(x)$", color="red", linewidth=2) # X和Y坐标轴plt.xlabel("x")plt.ylabel("sin(x) and cos(x)") # 图表的标题plt.title("sin and cos") # Y轴的范围plt.ylim(-1.5, 1.5)plt.xlim(0,4*np.pi) # 显示图示plt.legend() # 显示图plt.show() |
---|
解释一下其中的函数:
numpy.linspace(start, stop, num, endpoint=True, retstep=False, dtype=None)
在指定的间隔内返回均匀间隔的数字,在[start, stop]返回num均匀分布的样本。即在x从0-4Π中返回100个均匀分布的点。
numpy.sin(t)
这个就很好理解了,根据t值来确定sin的函数值。同理numpy.cos也是。
那么前三行的意思就是画0-4Π范围上的sin,cos的图。
plt.plot(x,y,format_string,**kwargs) x轴数据,y轴数据,format_string控制曲线的格式字串 format_string 由颜色字符,风格字符,和标记字符 ,下面有链接介绍。
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot
不过这些图像好像没什么意思??
所以我们找到了笛卡尔爱心曲线(-.-嘿嘿嘿嘿嘿嘿 十八禁)
于是代码就出来了:
Python
import matplotlib.pyplot as plt from matplotlib import animation import numpy as np import math def drawHeart(): t = np.linspace(0, math.pi, 1000) x = np.sin(t) y = np.cos(t) + np.power(x, 2.0/3) plt.plot(x, y, color='red', linewidth=2, label='h') plt.plot(-x, y, color='red', linewidth=2, label='-h') plt.xlabel('t') plt.ylabel('h') plt.ylim(-2, 2) plt.xlim(-2, 2) plt.title("爱心曲线",fontproperties='SimHei') plt.show() drawHeart()
123456789101112131415161718 | import matplotlib.pyplot as pltfrom matplotlib import animationimport numpy as npimport math def drawHeart(): t = np.linspace(0, math.pi, 1000) x = np.sin(t) y = np.cos(t) + np.power(x, 2.0/3) plt.plot(x, y, color='red', linewidth=2, label='h') plt.plot(-x, y, color='red', linewidth=2, label='-h') plt.xlabel('t') plt.ylabel('h') plt.ylim(-2, 2) plt.xlim(-2, 2) plt.title("爱心曲线",fontproperties='SimHei') plt.show()drawHeart() |
---|
这段代码就是用数学函数计算出具体值,然后画出来一个爱心。
我们发现这还不够好玩(nan),有没有更好玩的,可以更考(ke)验(yi)技(de)术(se)的呢?自然有啦,人的天性本就如此。所以我们找到了图片转化字符的样例,就是一张图片转化为字符存到文本里,实现用字符实现对图片的转化。而我们怎么进行对图片的处理呢?由此,我们用到了pillow库(又学到了)。
要知道Pillow库,首先要知道PIL。
PIL:Python imaging Library 即python的图像处理库。
Pillow 是PIL派生的一个分支,支持3以上Python版本。
Pillow库支持相当多的图片格式。直接使用Image模块中的open()函数读取图片,而不必先处理图片的格式,Pillow库自动根据文件决定格式。
Image模块中的save()函数可以保存图片,除非你指定文件格式,那么文件名中的扩展名用来指定文件格式。
例:
Python
im = Image.open('demo.gif') im.save('demo.BMP')
12 | im = Image.open('demo.gif')im.save('demo.BMP') |
---|
回到正题上,我们要处理图片,让其用字符填充,那么字符一定不能填充其颜色,也就是说,我们用字符去生成的图片只是黑白的。那么,我们就要将图片转化为黑白的,然后一个一个的对比并填充,所以我们用到了模式转换函数。即:
Python
# 黑白 img = Image.open('s.png') img.show() #原图,为彩色的 img = img.convert("L") img.show() #转换后的,只有黑白
12345 | # 黑白img = Image.open('s.png')img.show() #原图,为彩色的img = img.convert("L")img.show() #转换后的,只有黑白 |
---|
这样就完成了我们关键的第一步,接下来就开始进行对比。
在这里有一个重要的函数getpixel,该函数检索指定坐标点的像素的RGB颜色值。然后下面对比选取相应坐标的字符值即可。
接下来只要每个位置对比,选取合适的字符去填充就完成了整个操作。
下面为完整代码:
Python
from PIL import Image #要索引的字符列表 ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ") #获取字符列表的长度 length = len(ascii_char) #读取图像文件 img = Image.open('time.jpg') #对图像进行一定缩小,图片的大小可以根据上传图片的大小来按需调节 (width,height) = img.size img = img.resize((int(width*0.5),int(height*0.2))) print(img.size) def convert(img): img = img.convert("L") # 转为灰度图像 txt = "" for i in range(img.size[1]): for j in range(img.size[0]): gray = img.getpixel((j, i)) # 获取每个坐标像素点的灰度 unit = 256.0 / length txt += ascii_char[int(gray / unit)] #获取对应坐标的字符值 txt += '\n' return txt txt = convert(img) f = open("demo.txt","w") f.write(txt) #存储到文件中 f.close()
1234567891011121314151617181920212223242526 | from PIL import Image#要索引的字符列表ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")#获取字符列表的长度length = len(ascii_char)#读取图像文件img = Image.open('time.jpg')#对图像进行一定缩小,图片的大小可以根据上传图片的大小来按需调节(width,height) = img.sizeimg = img.resize((int(width*0.5),int(height*0.2))) print(img.size)def convert(img): img = img.convert("L") # 转为灰度图像 txt = "" for i in range(img.size[1]): for j in range(img.size[0]): gray = img.getpixel((j, i)) # 获取每个坐标像素点的灰度 unit = 256.0 / length txt += ascii_char[int(gray / unit)] #获取对应坐标的字符值 txt += '\n' return txt txt = convert(img)f = open("demo.txt","w")f.write(txt) #存储到文件中f.close() |
---|
pillow还有很多对图片处理的强大作用,还没了解完,这里就不一一贴出来了。
https://www.jianshu.com/p/f03f7f52d465
此为总结链接,方便以后查看。
那么在实现了用字符去填充图片后,我们自然会想到,可不可以用图片去填充图片呢??
当然可以,这就是千图成像技术,用非常多图片拼成一个大图。
代码非常的短,其实核心思想是差不多的,只需要将字符填充换为图像填充即可。
Python
from PIL import Image import os import random def get_img(path="./img_v2/save/"): img_file_list = os.listdir(path) tmp = path+random.choice(img_file_list) return Image.open(tmp) if __name__ == '__main__': width,height = int(458*320/10), int(537*240/10) test_im = Image.new("RGB", (width,height), "#ffffff") peiqi_img = Image.open("a.jpg").convert("L") for i in range(0,width,100): for j in range(0,height,100): tmp_i,tmp_j = int(i/32),int(j/24) gray = peiqi_img.getpixel((tmp_i,tmp_j)) if gray < 230: test_im.paste(get_img(),(i,j)) test_im.save("tmp.jpg")
12345678910111213141516171819 | from PIL import Imageimport osimport randomdef get_img(path="./img_v2/save/"): img_file_list = os.listdir(path) tmp = path+random.choice(img_file_list) return Image.open(tmp)if __name__ == '__main__': width,height = int(458*320/10), int(537*240/10) test_im = Image.new("RGB", (width,height), "#ffffff") peiqi_img = Image.open("a.jpg").convert("L") for i in range(0,width,100): for j in range(0,height,100): tmp_i,tmp_j = int(i/32),int(j/24) gray = peiqi_img.getpixel((tmp_i,tmp_j)) if gray < 230: test_im.paste(get_img(),(i,j)) test_im.save("tmp.jpg") |
---|
若精度不够高,拼成的图片效果不好,则可以对图片进行裁剪处理:
Python
#把图片全部剪切为100*100格式存到img_v2/save目录下 循环时也以100为步长 这样会调整精度 readPath='./img_v2/img/' savePath='./img_v2/save/' files=os.listdir(readPath) n=0 for file in files: n+=1 imgPath=readPath+ "\\" + file img=cv2.imread(imgPath) img=cv2.resize(img,(100,100))#更改图片的大小 cv2.imwrite(savePath+ "\\"+file,img) print(n)#查看循环情况
123456789101112 | #把图片全部剪切为100*100格式存到img_v2/save目录下 循环时也以100为步长 这样会调整精度readPath='./img_v2/img/'savePath='./img_v2/save/'files=os.listdir(readPath)n=0for file in files: n+=1 imgPath=readPath+ "\\" + file img=cv2.imread(imgPath) img=cv2.resize(img,(100,100))#更改图片的大小 cv2.imwrite(savePath+ "\\"+file,img) print(n)#查看循环情况 |
---|
这里也用到了os库,os库是Python标准库,包含几百个函数,常用路径操作、进程管理、环境参数等几类。os.path子库以path为入口,用于操作和处理文件路径。关于os库的一些常用函数可以看这里
https://www.jianshu.com/p/2b12a065ea22
还用到了OpenCV库,OpenCV是一个用于图像处理、分析、机器视觉方面的开源函数库。它的常用函数看这里
https://www.cnblogs.com/lufengyu/p/11495148.html
写的第一篇博客,技术干货真心不多,可以说是小白入门篇。在技术方面我知道了python作为超级语言的优势,但更多的是在心理方面上的感受。在写这些程序的时候,我完成了思维的转变,这个意义对我来说很大。做这些小程序,虽然小,但是给我的进步却很大。当你从知道它 ->了解它 -> 实现它 经过这三步转变后,你会发现有些东西其实也没有那么的神秘。有时候越学越发现自己的弱小,从而很容易不知疲倦的去学习它(突然想到人生苦短,我学python)。可以如果说不逼自己一把去试试,真的不知道代码原来可以这么精彩。。。
那是不是只有逼自己一把,才能发现世界原来那么精彩呢?
我已经准备好了。