美文网首页
python生成马赛克图片

python生成马赛克图片

作者: Aedda | 来源:发表于2020-10-27 13:54 被阅读0次

    下方注释的是爬取图片的爬虫
    爬取的图片集放在同级目录image文件夹下,每一个像素点都是一个图片

    import os
    import sys
    import time
    import math
    import numpy as np
    from PIL import Image, ImageOps
    from multiprocessing import Pool
    from colorsys import rgb_to_hsv, hsv_to_rgb
    from typing import List, Tuple, Union
    
    
    
    class mosaic(object):
        """定义计算图片的平均hsv值
        """
        def __init__(self, IN_DIR: str, OUT_DIR: str, SLICE_SIZE: int, REPATE: int,OUT_SIZE: int) -> None:
            self.IN_DIR = IN_DIR  # 原始的图像素材所在文件夹
            self.OUT_DIR = OUT_DIR  # 输出素材的文件夹, 这些都是计算过hsv和经过resize之后的图像
            self.SLICE_SIZE = SLICE_SIZE  # 图像放缩后的大小
            self.REPATE = REPATE  # 同一张图片可以重复使用的次数
            self.OUT_SIZE = OUT_SIZE  # 最终图片输出的大小
    
        def resize_pic(self, in_name: str, size: int) -> Image:
            """转换图像大小
            """
            img = Image.open(in_name)
            img = ImageOps.fit(img, (size, size), Image.ANTIALIAS)
            return img
    
        def get_avg_color(self, img: Image) -> Tuple[float, float, float]:
            """计算图像的平均hsv
            """
            width, height = img.size
            pixels = img.load()
            if type(pixels) is not int:
                data = []  # 存储图像像素的值
                for x in range(width):
                    for y in range(height):
                        cpixel = pixels[x, y]  # 获得每一个像素的值
                        data.append(cpixel)
                h = 0
                s = 0
                v = 0
                count = 0
                for x in range(len(data)):
                    r = data[x][0]
                    g = data[x][1]
                    b = data[x][2]  # 得到一个点的GRB三色
                    count += 1
                    hsv = rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
                    h += hsv[0]
                    s += hsv[1]
                    v += hsv[2]
    
                hAvg = round(h / count, 3)
                sAvg = round(s / count, 3)
                vAvg = round(v / count, 3)
    
                if count > 0:  # 像素点的个数大于0
                    return (hAvg, sAvg, vAvg)
                else:
                    raise IOError("读取图片数据失败")
            else:
                raise IOError("PIL 读取图片数据失败")
    class create_image_db(mosaic):
        """创建所需要的数据
        """
        def __init__(self, IN_DIR: str, OUT_DIR: str, SLICE_SIZE: int, REPATE: int,
                     OUT_SIZE: int) -> None:
            super(create_image_db, self).__init__(IN_DIR, OUT_DIR, SLICE_SIZE,
                                                  REPATE, OUT_SIZE)
    
        def make_dir(self) -> None:
            os.makedirs(os.path.dirname(self.OUT_DIR), exist_ok=True) # 没有就创建文件夹
    
        def get_image_paths(self) -> List[str]:
            """获取文件夹内图像的地址
            """
            paths = []
            suffixs = ['png', 'jpg']
            for file_ in os.listdir(self.IN_DIR):
                # suffix = file_.split('.')[-1]  # 获得文件后缀
                # if suffix in suffixs:  # 通过后缀判断是否是图片
                if file_.endswith('jpg'):
                    paths.append(os.path.join(self.IN_DIR,file_))  # 添加图像路径
                else:
                    print("非图片:%s" % file_)
            if len(paths) > 0:
                print("一共找到了%s" % len(paths) + "张图片")
            else:
                raise IOError("未找到任何图片")
    
            return paths
    
        def convert_image(self, path):
            """转换图像大小, 同时计算一个图像的平均hsv值.
            """
            try:
                img = self.resize_pic(path, self.SLICE_SIZE)
                color = self.get_avg_color(img)
                img.save(str(self.OUT_DIR) + str(color) + ".png")
            except:
                pass
    
        def convert_all_images(self) -> None:
            """将所有图像进行转换
            """
            self.make_dir()
            paths = self.get_image_paths()
            print("正在生成马赛克块...")
            pool = Pool()  # 多进程处理
            pool.map(self.convert_image, paths)  # 对已有的图像进行处理, 转换为对应的色块
            pool.close()
            pool.join()
    
    
    class create_mosaic(mosaic):
        """创建马赛克图片
        """
        def __init__(self, IN_DIR: str, OUT_DIR: str, SLICE_SIZE: int, REPATE: int,
                     OUT_SIZE: int) -> None:
            super(create_mosaic, self).__init__(IN_DIR, OUT_DIR, SLICE_SIZE, REPATE,
                                               OUT_SIZE)
    
        def read_img_db(self) -> List[List[Union[float, int]]]:
            """读取所有的图片
            """
            img_db = []  # 存储color_list
            for file_ in os.listdir(self.OUT_DIR):
                if file_ == 'None.png':
                    pass
                else:
                    file_ = file_.split('.png')[0]  # 获得文件名
                    file_ = file_[1:-1].split(',')  # 获得hsv三个值
                    file_ = [float(i) for i in file_]
                    file_.append(0)  # 最后一位计算图像使用次数
                    img_db.append(file_)
            return img_db
    
        def find_closiest(self, color: Tuple[float, float, float],
                          list_colors: List[List[Union[float, int]]]) -> str:
            """寻找与像素块颜色最接近的图像
            """
            FAR = 10000000
            for cur_color in list_colors:  # list_color是图像库中所以图像的平均hsv颜色
                n_diff = np.sum((color - np.absolute(cur_color[:3]))**2)
                if cur_color[3] <= self.REPATE:  # 同一个图片使用次数不能太多
                    if n_diff < FAR:  # 修改最接近的颜色
                        FAR = n_diff
                        cur_closer = cur_color
            cur_closer[3] += 1
            return "({}, {}, {})".format(cur_closer[0], cur_closer[1],
                                         cur_closer[2])  # 返回hsv颜色
    
        def make_puzzle(self, img: str) -> bool:
            """制作拼图
            """
            img = self.resize_pic(img, self.OUT_SIZE)  # 读取图片并修改大小
            color_list = self.read_img_db()  # 获取所有的颜色的list
    
            width, height = img.size  # 获得图片的宽度和高度
            print("Width = {}, Height = {}".format(width, height))
            background = Image.new('RGB', img.size,
                                   (255, 255, 255))  # 创建一个空白的背景, 之后向里面填充图片
            total_images = math.floor(
                (width * height) / (self.SLICE_SIZE * self.SLICE_SIZE))  # 需要多少小图片
            now_images = 0  # 用来计算完成度
            for y1 in range(0, height, self.SLICE_SIZE):
                for x1 in range(0, width, self.SLICE_SIZE):
                    try:
                        # 计算当前位置
                        y2 = y1 + self.SLICE_SIZE
                        x2 = x1 + self.SLICE_SIZE
                        # 截取图像的一小块, 并计算平均hsv
                        new_img = img.crop((x1, y1, x2, y2))
                        color = self.get_avg_color(new_img)
                        # 找到最相似颜色的照片
                        close_img_name = self.find_closiest(color, color_list)
                        close_img_name = self.OUT_DIR + str(
                            close_img_name) + '.png'  # 图片的地址
                        paste_img = Image.open(close_img_name)
                        # 计算完成度
                        now_images += 1
                        now_done = math.floor((now_images / total_images) * 100)
                        r = '\r[{}{}]{}%'.format("#" * now_done,
                                                 " " * (100 - now_done), now_done)
                        sys.stdout.write(r)
                        sys.stdout.flush()
                        background.paste(paste_img, (x1, y1))
                    except IOError:
                        print('创建马赛克块失败')
            # 保持最后的结果
            background.save('out_without_background.jpg')
            img = Image.blend(background, img, 0.5)
            img.save('out_with_background.jpg')
            return True
    
    if __name__ == "__main__":
        filePath = os.path.dirname(os.path.abspath(__file__))  # 获取当前的路径
        start_time = time.time()  # 程序开始运行时间, 记录一共运行了多久
        # 创建马赛克块, 创建素材库
        createdb = create_image_db(IN_DIR=os.path.join(filePath, 'images/'),
                                   OUT_DIR=os.path.join(filePath, 'outputImages/'),
                                   SLICE_SIZE=100,
                                   REPATE=20,
                                   OUT_SIZE=8000)
        createdb.convert_all_images()
        # 创建拼图 (这里使用绝对路径)
        createM = create_mosaic(IN_DIR=os.path.join(filePath, 'images/'),
                               OUT_DIR=os.path.join(filePath, 'outputImages/'),
                               SLICE_SIZE=100,
                               REPATE=20,
                               OUT_SIZE=8000)
        out = createM.make_puzzle(img=os.path.join(filePath, '微信图片_20201027102845.jpg'))
        # 打印时间
        print("耗时: %s" % (time.time() - start_time))
        print("已完成")
    
        # 爬图片
        # from urllib import request
        # from common import Common
        # import datetime
        #
        # driver = Common.get_driver('chrome')
        # driver.get('https://pic.sogou.com/pics?ie=utf8&p=40230504&interV=kKIOkrELjboMmLkEkrsTkKIMkLELjboImLkEk74TkKIMkrELjbkRmLkEmrELjbgRmLkEkLYTLlDpFEPQjb0E0vcGwOVFmVnmMz7lWaIPjf9QxeVPz6R7zOMTKVeRFTbxHUwElKJ6wu9DxqRLzO1H1qR7zOM%3D_923767100&query=%E9%A3%9E%E8%BD%A6')
        # end_time = datetime.datetime.now() + datetime.timedelta(seconds=15)
        # while True:
        #     driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
        #     time.sleep(0.2)
        #     if datetime.datetime.now() > end_time:
        #         time.sleep(3)
        #         break
        # f = 0
        # for i in driver.find_elements_by_xpath('//img[@src]'):
        #     try:
        #         url = i.get_attribute('src')
        #         request.urlretrieve(url, f'images\\sougou{f}.jpg')
        #         print(f)
        #         f+=1
        #     except:
        #         print('出错')
    
    
    
    
    

    相关文章

      网友评论

          本文标题:python生成马赛克图片

          本文链接:https://www.haomeiwen.com/subject/ufcxvktx.html