python 特效之千图成像

什么是 千图成像

使用 python 处理上千图片,将其最终合成一张图片,新图片放大后,可以看到每一张小图。


一、特效预览

python 特效之千图成像

处理后

python 特效之千图成像

细节放大后


二、程序原理

  • 将原图切割成一个一个的小块
  • 在上千张的图库中找到最相似的一块,将其替换掉
  • 而难点就在于找怎么找最相似的照片,当然最普通的就是以颜色为基准,找颜色最相似的照片
  • 缺点在于当图库的图片较少,而原图切割的块数较多时,图片重复比对的次数较多,会耗费大量的时间增加 cpu 的负荷
  • 我们可以将图库中的所有照片进行缩放,然后记录缩放照片的信息,并用这些信息给照片命名,这样会减少重复比对的次数

python 特效之千图成像

你听懂了吗


三、程序源码

#!/usr/bin/env python
# encoding: utf-8

import os
from PIL import Image
import numpy as np

class thousandMapImaging:
    def __init__(self):
        self.picture_path = 'assets/picture.jpeg'
        self.thousand_picture_path = 'assets/images/'

    def compute_mean(self, imgPath):
        '''
        获取图像平均颜色值
        :param imgPath: 缩略图路径
        :return: (r,g,b)整个缩略图的rgb平均值
        '''
        im = Image.open(imgPath)
        im = im.convert('RGB')  # 转为 rgb模式
        # 把图像数据转为数据序列。以行为单位,每行存储每个像素点的色彩
        '''如:
         [[ 60  33  24] 
          [ 58  34  24]
          ...
          [188 152 136] 
          [ 99  96 113]]
    
         [[ 60  33  24] 
          [ 58  34  24]
          ...
          [188 152 136] 
          [ 99  96 113]]
        '''
        imArray = np.array(im)
        # mean()函数功能:求指定数据的取均值
        R = np.mean(imArray[:, :, 0])  # 获取所有 R 值的平均值
        G = np.mean(imArray[:, :, 1])
        B = np.mean(imArray[:, :, 2])
        return (R, G, B)


    def getImgList(self):
        """
        获取缩略图的路径及平均色彩
        :return: list,存储了图片路径、平均色彩值。
        """
        imgList = []
        for pic in os.listdir(self.thousand_picture_path):
            imgPath = self.thousand_picture_path + pic
            imgRGB = self.compute_mean(imgPath)
            imgList.append({
                "imgPath": imgPath,
                "imgRGB": imgRGB
            })
        return imgList


    def computeDis(self, color1, color2):
        '''
        计算两张图的颜色差,计算机的是色彩空间距离。
        dis = (R**2 + G**2 + B**2)**0.5
        参数:color1,color2 是色彩数据 (r,g,b)
        '''
        dis = 0
        for i in range(len(color1)):
            dis += (color1[i] - color2[i]) ** 2
        dis = dis ** 0.5
        return dis


    def create_image(self, bgImg, imgDir, N=10, M=50):
        '''
        根据背景图,用头像填充出新图
        bgImg:背景图地址
        imgDir:头像目录
        N:背景图缩放的倍率
        M:头像的大小(MxM)
        '''
        # 获取图片列表
        imgList = self.getImgList()

        # 读取图片
        bg = Image.open(bgImg)
        # bg = bg.resize((bg.size[0] // N, bg.size[1] // N))  # 缩放。建议缩放下原图,图片太大运算时间很长。
        bgArray = np.array(bg)
        width = bg.size[0] * M  # 新生成图片的宽度。每个像素倍放大 M 倍
        height = bg.size[1] * M  # 新生成图片的高度

        # 创建空白的新图
        newImg = Image.new('RGB', (width, height))

        # 循环填充图
        for x in range(bgArray.shape[0]):  # x,行数据,可以用原图宽替代
            for y in range(bgArray.shape[1]):  # y,列数据,,可以用原图高替代
                # 找到距离最小的图片
                minDis = 10000
                index = 0
                for img in imgList:
                    dis = self.computeDis(img['imgRGB'], bgArray[x][y])
                    if dis < minDis:
                        index = img['imgPath']
                        minDis = dis
                # 循环完毕,index 就是存储了色彩最相近的图片路径
                #         minDis 存储了色彩差值
                # 填充
                tempImg = Image.open(index)  # 打开色差距离最小的图片
                # 调整图片大小,此处可以不调整,因为我在下载图的时候就已经调整好了
                tempImg = tempImg.resize((M, M))
                # 把小图粘贴到新图上。注意 x,y ,行列不要搞混了。相距 M 粘贴一张。
                newImg.paste(tempImg, (y * M, x * M))
                print('(%d, %d)' % (x, y))  # 打印进度。格式化输出 x,y

        # 保存图片
        newImg.save('final.jpg')  # 最后保存图片

    def hello(self):
        '''
        This is a welcome speech
        :return: self
        '''
        print('*' * 50)
        print(' ' * 20 + '千图成像')
        print(' ' * 5 + 'Author: autofelix  Date: 2022-01-14 13:14')
        print('*' * 50)
        return self

    def run(self):
        '''
        The program entry
        '''
        self.create_image(self.picture_path, self.thousand_picture_path)

if __name__ == '__main__':
    thousandMapImaging().hello().run()
上一篇:.net core 集成 sentry 进行异常报警


下一篇:python 特效之图片处理