基于Python PIL库的简易马赛克拼图程序

基于Python Pillow库的马赛克拼图程序

期末需要完成一个Python有关的小项目,对Python图片处理库比较感兴趣,所以选择了这个程序。
基本思路分两步:第一步用request库,爬取搜狗图片库图片,并保存到本地图片库。第二步是根据已有图片,运用pillow库搜索图片库中的图片,拼接出所选图片。

实现效果:

在这里插入图片描述

原始图片

在这里插入图片描述

一.爬取网页图片

在Python3.6环境下,以搜狗壁纸为爬取对象。
(选择壁纸网站,考虑到后期拼图,壁纸网站提供的图片大小统一,方便拼图)

我选择了壁纸分类,现在开始F12阅读网页代码进行分析。
在这里插入图片描述
检查图片元素后发现图片的src存放在img标签下,然后尝试使用requests组件获取此img标签,进而提取图片的src地址再使用 urllib.request.urlretrieve逐个下载图片,从而达到批量获取资料的目的。

import requests
from bs4 import BeautifulSoup
res = requests.get('http://pic.sogou.com/pics/recommend?category=%B1%DA%D6%BD')
soup = BeautifulSoup(res.text,'html.parser')
print(soup.select('img'))

输出:
在这里插入图片描述

运行后发现并得不到所需要的图片src,只得到图片的img信息,可能网页采取了动态元素,图片原始src并不在当前链接下。然后开始了对图片原始src的漫长探索过程,最后在多方网友帖子的指导下,找到位置 F12→Network→XHR→点击一个文件的Preview

在这里插入图片描述
然后在bthumbURL标签终于得到了图片的原始链接,在访问这个链接后,确认得到的是所需要的图片。在访问图示链接后,显示的是小图,应该是预览图,后发现原始图片链接在下面ori_pic_url标签下,由于拼图程序对图片质量要求不高,我还是采用图示链接,图片小也方便下载

但是问题出现了,我得不到XHR→preview下的链接,后又在多方查询下,发现Preview标签左边的Header标签里面有网页原始链接。
在这里插入图片描述
得到这个Request URL,去掉URL中不需要的部分,分析链接,字面意思,知道category后面可能为壁纸这个大的图片分类,tag后面为壁纸的标签(分类),start为开始下标,len为长度,也即图片的数量。

由此我们可以添加选择图片分类的功能,只需要用户输入tag的分类就完成了。

访问页面得到:
在这里插入图片描述
然后在这个网页里,终于可以在bthumbURL标签下得到获取图片的url了
下面是批量下载搜狗壁纸的完整代码:

import requests
import json
import urllib
import os
import sys

def getSogouImage(category,tag,length,path):
    n = length
    cate = category
    print('http://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category='+cate+'&tag='+tag+'&start=0&len='+str(n))
    imgs = requests.get('https://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category='+cate+'&tag='+tag+'&start=0&len='+str(n))
    jd = json.loads(imgs.text)
    jd = jd['all_items']
    imgs_urls = []
    for j in jd:
        imgs_urls.append(j['bthumbUrl'])
    m = 0
    for img_url in imgs_urls:
            print('***** '+str(m)+'.jpg *****'+'   Downloading...')
            urllib.request.urlretrieve(img_url,path+str(m)+'.jpg')
            m = m + 1
    print('Download complete!')


workPath = sys.path[0]
if not os.path.exists(workPath + "\imgs"):
    os.mkdir(workPath + "\imgs")

tag = input("请输入所下载壁纸分类:(全部,世界风光,动物,明星,汽车,动漫,游戏等):")
amount = input("请输入下载张数(整数):")
print("下载到当前目录img\目录下")
getSogouImage('壁纸', tag, amount, workPath + "\imgs\\")

output:
在这里插入图片描述

二.马赛克拼图程序

思路其实很简单,就是将目标图片分割成均匀小块,再从已有的本地图片库中根据RGB,灰度搜索图库中最匹配的图片进行替换,每个小块都替换好了,整个图片也就拼好了。
所以这部分程序分为三个部分:
1.处理原始图片
2.搜索图库进行匹配
3.替换每个小块,生成新的图片

1.处理原始图片

思路是获取到图片的分辨率后,计算出图片的长宽的最大公约数(GCD)。例如原始图片为1920* 1080,GCD为120,则长宽都由,120张图片拼出来,这样计算出来每个小图的尺寸为16* 9。为防止小图尺寸过小,设置一个参数min_unit,为小图长宽的倍数。若min_unit = 5,则此例中小图最终尺寸为80*45,然后每行图片数量为120/5=24张。所以min_unit也可理解为最终图片的精细度,数值越小,每一行的图片越多,最终图片密度越大。(设置了一个flag,如果原图无法正常计算处理,返回flag = false,这个时候需要手动输入参数小图尺寸)

# 计算子图大小
    def __divide_sub_im(self, width, height):
        flag = True
        g = self.__gcd(width, height)
        if g < 20:
            flag = False
            width = self.__default_w
            height = self.__default_h
            g = 320

        if g == width:
            g = 320
        self.__sub_width = self.__min_unit * (width // g)
        self.__sub_height = self.__min_unit * (height // g)
        return flag

    # 辗转相除法求最大公约数
    @staticmethod
    def __gcd(a, b):
        while a % b:
            a, b = b, a % b
        return b

2.读取本地图库

参数有3个,本地图库路径,上一个方法确定的小图最终长宽。根据参数,对图库所有图片resize,方便后期小图拼接。

    # 读取全部图片保存, fin_w,fin_h素材最终尺寸
    def __read_all_img(self, db_path, fin_w, fin_h):
        files_name = os.listdir(db_path)
        n = 1
        # 开启5个线程加载图片
        ts = list()
        for i in range(5):
            ts.append(list())
        for file_name in files_name:
            full_path = db_path + "\\" + file_name
            if os.path.isfile(full_path):
                read_task = self.__ReadTask(n, full_path
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值