开发者社区> autofelix> 正文

python 特效之千图成像

简介: 手机里女票的照片终于可以派得上用场了
+关注继续查看

什么是 千图成像

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


一、特效预览

Snipaste_2022-01-13_12-30-48.png

处理后

Snipaste_2022-01-14_19-12-53.png

细节放大后


二、程序原理

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

dance.gif

你听懂了吗


三、程序源码

#!/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()

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
9408 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18349 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
17080 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
24938 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
21583 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
18838 0
+关注
autofelix
关注我,一起零基础学编程~
62
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载