• Python 让书法作品和 PIL 库来一场美丽的邂逅


    1. 前言

    不久之前写过一篇文章,详细介绍了 PIL 库中的 Image 模块的使用。曾经学习过、使用过一段时间的 PS,认识 PIL 后,觉得这这玩意太好玩了,有了想使用 PIL 库实现 PS 中的图片特效的想法。

    好,现在直接上案例,不另废其它话。

    2. 遮罩图片

    本文案例中所用的图片素材,取自于我舅舅的书法作品(有点小名气的书法家)。

    第一张书法作品:心佛。

    这张心中有佛的作品,我只需要上面的佛字,进行后续操作之前,首要任务是截取佛字,也就整张图片的上面一部分。

    这里使用两种方案实现。

    2.1 使用 Image 模块的裁剪方法

    此方法简单直接,裁剪时需要指定裁剪的矩形区域,左上角坐标容易确定(0,0),右下角的坐标这里就大概判断,眼观一下,佛字大概是整幅作品的 四 分之一。

    也可以稍精准的计算机出右下角的位置。

    佛字和下面的内容之间有一条较完整的白色分割区域。可以从上向下以行为单位扫描整幅图片,如果发现那一行像素点的 R,G,B 的值近似相等且值都大于 200 以上,则可判断出位置。有兴趣者可以试试。

    from PIL import Image
    # 打开原图片
    fo_img = Image.open("fo.jpg")
    # 因后续要使用此图片做遮罩,需要透明通道,所以要转换成 RGBA 模式 
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # h/4-55 完全是试出来的偏差值 
    fo_img = fo_img.crop((0, 0, w, h / 4 - 55))
    fo_img.show()
    

    如下是裁剪出来的图片效果。

    2.2 一个像素点一个像素点的裁剪

    当把 RGB 模式转换成 RGBA 模式后,Python 解释器会给多出来的 a 通道赋值 255 。

    因后面要使用这个佛字做遮罩。这里需要把佛字图片中的白色区域的 a 通道值修正为 0(白色区域全部变成透明区域)。

    因是书法图片,整张图片整体上呈现明显的黑白两极分布,白色区域的 R、G、B 分量值大概是在 200 左右,黑色文字的 R,G,B 颜色分量值大概在 100 以下。

    Tip: 当使用一张图片做遮罩时,图片的 a 通道值为 0 的地方,被遮罩图片所遮住的图片会变成透明。a 通道为 255 的地方,表示完全不透明,从 0 到 255 之间由透明逐渐梯度变成不透明。

    from PIL import Image
    fo_img = Image.open("fo.jpg")
    # 先转换成 RGBA 模式
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # 创建一张空白的新图片,大小和要裁剪的佛字图片一样大小
    fo_only_img = Image.new(fo_img.mode, (w, int(h / 4) - 55))
    w, h = fo_only_img.size
    for i in range(w):
        for j in range(h):
            # 获取每一像素点的颜色分量
            r, g, b, a = fo_img.getpixel((i, j))
            # 把白色区域的 a 值修改为 0 ,白色区域的R,G,B值相近
            if r > 180 or g>180 or b>180:
                a = 0
            # 为新图片指定新的颜色模式
            fo_only_img.putpixel((i, j), (r, g, b, a))
    fo_only_img.show()
    

    以上代码需注意,截取出来的图片数据被写入一张新图片中。

    两种方案比较:

    • 第一种方案提取后,还是需要再修改每一个像素点的透明信息。

    • 第 2 种方案一步到位。

    处理完佛字图片后,再准备一张春归的书法作品做被遮罩图片。

    为了让便于理解遮罩图片与被遮罩图片的关系,这里画一个示意图。

    在如下的代码还会创建一张做背景的白色图片。

    from PIL import Image
    fo_img = Image.open("fo.jpg")
    # 先转换成 RGBA 模式
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # 创建一张空白的新图片,大小和要裁剪的佛字图片一样大小
    fo_only_img = Image.new(fo_img.mode, (w, int(h / 4) - 55))
    w, h = fo_only_img.size
    for i in range(w):
        for j in range(h):
            # 获取每一像素点的颜色分量
            r, g, b, a = fo_img.getpixel((i, j))
            # 把白色区域的 a 值修改为 0
            if r > 180:
                a = 0
            # 为新图片指定新的颜色模式
            fo_only_img.putpixel((i, j), (r, g, b, a))
    # 开始准备做遮罩效果之前,打开被遮罩图
    chun_gui_img = Image.open("chungui.jpg")
    # 修改 chun_gui_img 图片和遮罩图片一样大小
    chun_gui_img = chun_gui_img.resize(fo_only_img.size)
    # 创建一张新的、空白的、纯白色的背景图片
    new_img = Image.new("RGBA", chun_gui_img.size)
    # 开始粘贴
    new_img.paste(chun_gui_img, mask=fo_only_img)
    new_img.show()
    

    执行代码后,可看到如下的图片效果。这个效果在 PS 中更容易实现(毕竟人家是专业的图片处理软件)。

    几个变化:

    1. 反转效果

      前面是把佛字图片的白色区域的 a 值设定为 0,则白色区域所对应的春归图片会变成透明。现在反过来,把文字区域的 a 值设为 0。就可以看到和上图相反的一个效果。

    from PIL import Image
    import random
    
    fo_img = Image.open("fo.jpg")
    # 先转换成 RGBA 模式
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # 创建一张空白的新图片,大小和要裁剪的佛字图片一样大小
    fo_only_img = Image.new(fo_img.mode, (w, int(h / 4) - 55))
    w, h = fo_only_img.size
    # 步长值
    step = 1
    step1 = 1
    for i in range(0, w, 1):
        for j in range(h):
            # 获取每一像素点的颜色分量
            r, g, b, a = fo_img.getpixel((i, j))
            # 文字区域的 a 值设置为 0
            if r < 80:
                a = 0
            # 为新图片指定新的颜色模式
            fo_only_img.putpixel((i, j), (r, g, b, a))
    # 开始准备做遮罩效果之前,先打开底图
    chun_gui_img = Image.open("chungui.jpg")
    # 修改 chun_gui_img 图片和遮罩图片一样大小
    chun_gui_img = chun_gui_img.resize(fo_only_img.size)
    # 创建一张新的图片
    new_img = Image.new("RGBA", chun_gui_img.size,(100,200,80))
    # 开始粘贴
    new_img.paste(chun_gui_img, mask=fo_only_img)
    new_img.show()
    
    

    如果把背景颜色设置为金色,佛字就会变成金色。同理,可以选择任一喜欢的颜色。

    new_img = Image.new("RGBA", chun_gui_img.size,ImageColor.getrgb("gold"))
    

    1. 颗粒效果

    颗粒效果实现的思路和前面差不多,使用随机模块让文字区域的透明值随机变化,让文字区域有的地方透明,有的地方不透明,有的地方半透明。

    from PIL import Image
    import random
    fo_img = Image.open("fo.jpg")
    # 先转换成 RGBA 模式
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # 创建一张空白的新图片,大小和要裁剪的佛字图片一样大小
    fo_only_img = Image.new(fo_img.mode, (w, int(h / 4) - 55))
    w, h = fo_only_img.size
    print(w)
    # 步长值
    step = 1
    for i in range(0, w, 1):
        for j in range(h):
            # 获取每一像素点的颜色分量
            r, g, b, a = fo_img.getpixel((i, j))
            if r > 180:
                a = 0
            elif r < 100:
                # 随机
                a -= random.randint(0, 255)
            # 为新图片指定新的颜色模式
            fo_only_img.putpixel((i, j), (r, g, b, a))
    # 开始准备做遮罩效果之前,先打开底图
    chun_gui_img = Image.open("chungui.jpg")
    # 修改 chun_gui_img 图片和遮罩图片一样大小
    chun_gui_img = chun_gui_img.resize(fo_only_img.size)
    # 创建一张新的图片
    new_img = Image.new("RGBA", chun_gui_img.size)
    # 开始粘贴
    new_img.paste(chun_gui_img, mask=fo_only_img)
    new_img.show()
    
    

    3. 字符串图片

    把图片中的每一像素点用不同的字符串替换,然后保存字符串信息。如下代码中,白色区域的像素点使用“仁”字替换。黑色文字区域的像素点使用“佛”字替换。

    from PIL import Image
    import random
    fo_img = Image.open("fo.jpg")
    # 先转换成 RGBA 模式
    fo_img = fo_img.convert("RGBA")
    # 获取图片本身大小
    w, h = fo_img.size
    # 创建一张空白的新图片,大小和要裁剪的佛字图片一样大小
    fo_only_img = Image.new(fo_img.mode, (w, int(h / 4) - 55))
    w, h = fo_only_img.size
    # 步长值
    old_rgb = None
    s = ''
    for i in range(w):
        for j in range(h):
            # 获取每一像素点的颜色分量
            r, g, b, a = fo_img.getpixel((i, j))
            fo_only_img.putpixel((i, j), (r, g, b, a))
    
    fo_only_img = fo_only_img.resize((300, 300))
    w, h = fo_only_img.size
    for i in range(h):
        for j in range(w):
            r, g, b, a = fo_only_img.getpixel((j, i))
            if r > 100:
                s += "仁"
            else:
                s += '佛'
        s += "\n"
    with open("d:/fo.txt", 'w') as f:
        f.write(s)
    

    找到对应文本文件、打开、缩小,可以清晰看到一个大大的“佛”字。如果放大,则会发现,整个佛字是由很多小佛字组成。

    4. 总结

    编程与书法一样,都是一门艺术,艺术是为生活服务的。程序可以让人类的生活更方便,书法则可以让人类精神世界更美好。当两者碰在一起后,世界充满仁和爱。
    获取更多技术文章,请关注我的公众号!

  • 相关阅读:
    IDEA中添加servlet模板
    【强化学习】深度确定性策略梯度(DDPG)算法求解 Pendulum 问题 + Pytorch代码实战
    金仓数据库 KingbaseES 插件force_view
    酷安官网下载页前端自适应源码
    分布式 PostgreSQL - Citus 架构及概念
    计算点在线上的投影坐标
    英特尔参与 CentOS Stream 项目
    神经网络中的优化方法
    Python 操作 lxml库与Xpath(爬取网页指定内容)
    【零基础学Python】Day2 Python基本语法
  • 原文地址:https://www.cnblogs.com/guo-ke/p/16010919.html