【有点意思】Python Turtle+PIL ‘画图’之黄家驹

运用PIL的Image模块与turtle模块读取并重新画出图像

最终效果图(大概这样吧)

在这里插入图片描述

很早就有这个想法,现在被宅在家‘享受’假期,就实践一下。

思路是读取一张有人像的图片,然后通过循环对比,记录下人各行人像的像素坐标,然后再通过turtle画出大概的人像轮廓。

== *思来想去,翻来找去,发现Image模块有直接显示轮廓的函数,而且对于从图象中识别出人像,这个对于我这样的小白菜太难了,就掐头去尾,偷工减料,选取黑白或者是色彩单一、含人像的图像来识别(机cai智ji如我) ==
再来捋捋
步骤操作用到的库
1读取图像,通过遍历每一行像素记录并对比,得到画图所需的人像‘坐标’PIL
2根据所得到的坐标,调用turtle库画图turtle

对!就只有这两大步。

第一步,读取图片,获得画图坐标

在这里插入图片描述

读取图片如上,获取坐标是逐行遍历像素的过程,便利时记录每一行像素中非白色(白色为背景色)的像素条的始末坐标(X1,X2)。
对比时,当前像素与同行的下一个像素进行比较,如果两个像素值不同,且有一像素为背景色,那么记录非背景色的横坐标。
记录时,整张图的数据暂时保存在一个列表中,该列表由n个列表组成(n为图像像素行数),这n个列表存着对应行的所有非背景色像素条的始末坐标。

== 上码 ==

from PIL import Image
import turtle as t

def get_lst(img_path):
    imgf = Image.open(img_path)  # 读取图像
    global size
    print(size:= imgf.size) # 获取图像尺寸/大小
    pix = imgf.load()
    lst = [[] for i in range(size[1])] # 构造空列表
    for y in range(0, size[1]): # 从第一行开始循环
        index = 0
        for x in range(0, size[0]-1): # 循环第y行的每一个像素
            # 如果当前像素与下一个像素值不同且两者有一为背景色,则记录坐标
            if pix[x, y] != pix[x+1, y] and (255, 255, 255, 255) in [pix[x, y], pix[x+1, y]]:
                if index == 0: # index值为0说明是像素条起始坐标
                    lst[y].append([x+1, ])
                    index += 1
                else: # index值为1说明记录的是像素条结束坐标
                    lst[y][-1].append(x)
                    index = 0
    return lst

第二步,画图

得到了每一个像素条的始末坐标后,就可以逐行画图了

== 上码 ==

def paint(lst):
    fontc = 'whitesmoke' # 右边字的颜色
    manc = 'black' #'dimgrey' 人像的颜色
    t.setup(width=size[0]+40, height=size[1]) # 绘图窗口大小
    t.screensize(bg='oldlace') # 画布背景色
    t.bgpic(r'c:\users\pxo\desktop\bg.png') # 画布背景图
    t.speed(333) #画画速度 据说范围[1,10]
    for y in range(0, size[1]):
        # 遍历每一行
        t.pencolor(manc)
        for line in lst[y]:
            # 遍历每一个像素条
            if line[0] > 364 and 144 < y < 495: # 这个是判断是否是右边的字
                t.pencolor(fontc)
            # 下面是画像素条
            t.penup()
            t.goto(line[0]-size[0]//2, (size[1]-y)-size[1]//2)
            t.pendown()
            t.goto(line[1]-size[0]//2, (size[1]-y)-size[1]//2)
    t.mainloop()

然后就可以开始开始搞事了

if __name__ == '__main__':
    img_path = r'c:\users\pxo\desktop\jh.png' # 图像地址
    lst = get_lst(img_path)
    paint(lst)

附上一张带背景图的

背景粗糙就将就着看吧,哈哈哈哈
在这里插入图片描述

== |—> ==这并没有结束,后来我又想,如果不按顺序而是随机画线条,那岂不是有点意思。 开码:

from PIL import Image
import turtle as t
from random import choice


def get_lst(img_path):
    imgf = Image.open(img_path)
    global size
    print(size:= imgf.size)
    pix = imgf.load()
    lst = [[] for i in range(size[1])]
    for y in range(0, size[1]):
        index = 0
        for x in range(0, size[0]-1):
            if pix[x, y] != pix[x+1, y] and (255, 255, 255, 255) in [pix[x, y], pix[x+1, y]]:
                if index == 0:
                    lst[y].append([y, x+1, ]) # 这里在每一个像素条的数据中加入了其纵坐标y
                    index += 1
                else:
                    lst[y][-1].append(x)
                    index = 0
    # 这里也改了,返回的数据列表的子元素是所有单独的像素条,而不是某一行像素条的总和
    lt = []
    for i in lst:
        for j in i:
            if j:
                lt.append(j)
    return lt


def paint(lst):
    fontc = 'darkorange'
    manc = 'black' #'dimgrey'
    t.setup(width=size[0]+40, height=size[1]+40)
    t.screensize(bg='oldlace')
    #t.bgpic(r'c:\users\pxo\desktop\bg.png')
    t.speed(330)
    cnt = len(lst)
    lt = [i for i in range(cnt)] # 弄一个种子列表,理解为存取位置
    flst = []
    for i in range(cnt):
        del lt[lt.index(index:=choice(lt))] #获取并删除一个随机位置
        line = lst[index]  # 从所有线条中得到一条随机线条(像素条)
        y = line[0]
        x1, x2 = line[1], line[2]
        t.pencolor(manc)
        if x1 > 364 and 144 < y < 495:
            flst.append(line)
            continue
        t.penup()
        t.goto(x1-size[0]//2, (size[1]-y)-size[1]//2)
        t.pendown()
        t.goto(x2-size[0]//2, (size[1]-y)-size[1]//2)
    new_flst = sorted(flst[:-80], reverse=True)
    for line in new_flst:
        y = line[0]
        x1, x2 = line[1], line[2]
        t.pencolor(fontc)
        t.penup()
        t.goto(x1-size[0]//2, (size[1]-y)-size[1]//2)
        t.pendown()
        t.goto(x2-size[0]//2, (size[1]-y)-size[1]//2)
    t.hideturtle()
    t.mainloop()


if __name__ == '__main__':
    img_path = r'c:\users\pxo\desktop\jh.png'
    lst = get_lst(img_path)
    paint(lst)

改的地方也不是很多,就不详细讲了,将就着看注释吧,哈哈哈。

附几张画到一半的图

在这里插入图片描述
在这里插入图片描述

就这样了 == !_! ==

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Python海龟和OpenCV都是非常强大的绘图库。结合使用它们可以创建出非常酷炫的图像效果。下面是一个演示如何使用Python海龟和OpenCV来绘制图像的简单示例。 首先,我们需要导入所需的库: ```python import cv2 import numpy as np import turtle ``` 接下来,我们需要读取图像并将其转换为numpy数组,这可以使用OpenCV来完成: ```python img = cv2.imread('test.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ``` 然后,我们可以使用以下代码来绘制原始图像: ```python turtle.speed(0) turtle.hideturtle() turtle.penup() turtle.goto(-400, 0) turtle.pendown() for i in range(len(img)): for j in range(len(img[i])): turtle.color(img[i][j][0]/255, img[i][j][1]/255, img[i][j][2]/255) turtle.dot(5) turtle.penup() turtle.forward(5) turtle.pendown() turtle.penup() turtle.backward(len(img[i])*5) turtle.right(90) turtle.forward(5) turtle.left(90) turtle.pendown() ``` 这段代码会使用海龟绘图库,将图像绘制在屏幕上。这里我们使用了`turtle.dot(5)`函数来画出每个像素点。当然您可以修改这个数字来改变像素大小。 完整代码如下: ```python import cv2 import numpy as np import turtle img = cv2.imread('test.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) turtle.speed(0) turtle.hideturtle() turtle.penup() turtle.goto(-400, 0) turtle.pendown() for i in range(len(img)): for j in range(len(img[i])): turtle.color(img[i][j][0]/255, img[i][j][1]/255, img[i][j][2]/255) turtle.dot(5) turtle.penup() turtle.forward(5) turtle.pendown() turtle.penup() turtle.backward(len(img[i])*5) turtle.right(90) turtle.forward(5) turtle.left(90) turtle.pendown() turtle.done() ``` 这个示例只是一个简单的演示,您可以根据自己的需要对代码进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的壳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值