情人节要到了,为你的女友拼一张照片墙吧!

Posted Z.Q.Feng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了情人节要到了,为你的女友拼一张照片墙吧!相关的知识,希望对你有一定的参考价值。


前言

身为程序员,每天陪女友的时间还不如敲键盘的时间多,要想既敲键盘又能够哄好女友,生活中必要的关心还是必不可少的,那么,身为程序员的我们如何去巧妙的哄好自己的女朋友呢?

最终生成效果图如下:本代码同样适用于生成其他照片。

在这里插入图片描述

本文编译环境为 Python3.8.5,不同版本略有出入,望见谅。


一、pip安装相关库

本文中需要用到的相关库有:urllib,random,glob,PIL,numpy,cv2,os

若电脑编译环境缺省相关库可使用以下命令安装:

# 豆瓣高速源
pip3 install #相关缺省库# -i http://pypi.douban.com/simple --trusted-host pypi.douban.com 
# 中国科技大学高速源
pip3 install #相关缺省库# -i https://pypi.mirrors.ustc.edu.cn/simple/ --trusted-host pypi.mirrors.ustc.edu.cn 
# 阿里云 
pip3 install #相关缺省库# -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com 

二、照片准备

首先我们需要准备的是一系列需要进行拼图的照片,将这些照片存放在pictures 文件夹内(注意如果这里的文件夹名称更改了的话在后面代码中也需要更改哦)
在这里插入图片描述
可以看到这些照片的命名是五花八门的,所以,我们需要先对这些照片进行规范化处理,在这里我们编写一个脚本文件 rename.py 来辅助我们处理:

# coding = 'utf-8'
import os

def rename(path):
    i = 1
    '该文件夹下所有的文件(包括文件夹)'
    FileList = os.listdir(path)
    '遍历所有文件'
    for files in FileList:
        '原来的文件路径'
        oldDirPath = os.path.join(path, files)
        '文件扩展名'
        fileType = '.jpg'
        '新的文件路径'
        newDirPath = os.path.join(path, str(i) + fileType)
        '重命名'
        os.rename(oldDirPath, newDirPath)
        i += 1

# 注意这里的path是你的pictures文件夹所在的路径
path = '/home/zq/Documents/excample/pictures'
rename(path)

注意:文件里的 path 是你的 pictures文件夹所在路径,可以右键文件夹,然后属性即可查看。
在这里插入图片描述
运行 rename.py ,我们可以看到 pictures 文件夹中的照片被成功的规范命名。

在这里插入图片描述

二、图片拼接

接下编写我们的图片拼接脚本,主要思路如下:

1.引入库

import urllib,random, glob
from PIL import Image
import numpy as np
import cv2 as cv

2.变量设置

savepath = '/home/zq/Documents/excample/pictures/'  #图片存储位置
resultSavePath = '/home/zq/Documents/excample/result.png'   #生成图片存储位置
modePath = '/home/zq/Documents/excample/mode.jpg'    #模板存储位置

path_picture_number = glob.glob(savepath + '*.jpg') #获取图片文件夹内图片
# print(path_picture_number)
pictures_count = len(path_picture_number)   #图片数量
all_mean_rgbs = []   #存储计算出的所有平均rgb值

注意这里各个路径变量的值每个人的电脑是不同的,具体查看方式依旧是 右键->属性

3.功能函数

计算图片平均 rgb 函数:

def meanrbg(img):  #计算图片平均rgb
    rgb = np.array(img)
    r = int(round(np.mean(rgb[:, :, 0])))
    g = int(round(np.mean(rgb[:, :, 1])))
    b = int(round(np.mean(rgb[:, :, 2])))
    return (r,g,b)

存储图片函数:

def savaImg(picurl,saveurl):  #存储图片函数,picurl是图片的 URL,saveurl是本地存储位置
    try:
        bytes = urllib.request.urlopen(picurl)
        file = open(saveurl,'wb')
        file.write(bytes.read())
        file.flush()
        file.close()
        return True
    except:
        print('worry')
        savaImg(picurl,saveurl)

模板拼接函数:

def mode_split(filepackage,modepath,bigsize,littlesize):  #以模板存储头像
    row = bigsize[0] #大图每行多少个小头像
    col = bigsize[1] #每列
    suitSize = (littlesize*row,littlesize*col)  #大图最终的像素size
    bigImg = Image.open(modepath)
    bigImg = bigImg.resize(suitSize)
    resultImg = Image.new('RGBA',suitSize)

    for i in range(row):
        for j in range(col):
            cutbox = (i*littlesize,j*littlesize,(i+1)*littlesize,(j+1)*littlesize)  #模板剪切用于对比的某个区域
            cutImg = bigImg.crop(cutbox) #复制到cutImg中
            tmprgb = meanrbg(cutImg)
            suitOne = mostSuitImg(tmprgb) + 1  #对比出最合适的头像

            img = Image.open(filepackage + str(suitOne) + '.jpg').convert('RGBA')
            img = img.resize((littlesize,littlesize))
            resultImg.paste(img,cutbox)
            print('已粘贴',cutbox)

	resultImg.save(resultSavePath)  #存储

匹配图片函数:

def mostSuitImg(tmprgb):  #进行对比,找出最合适的头像
    global all_mean_rgbs
    minRange = 200000
    id = 0
    for rgb in all_mean_rgbs:
        tmp = (rgb[1][0]-tmprgb[2])**2+(rgb[1][1]-tmprgb[1])**2+(rgb[1][2]-tmprgb[1])**2
        if tmp<minRange:
            minRange = tmp
            id = rgb[0]
    return id

4.主函数

if __name__ == '__main__':
    #存放匹配图片 rgb 信息
    for i in range(1,pictures_count + 1):
        img = cv.imread(savepath+str(i)+'.jpg')
        rgb = meanrbg(img)
        all_mean_rgbs.append(rgb)
    all_mean_rgbs = list(enumerate(all_mean_rgbs))  #给列表增加一个索引
	
	v = 60; #生成照片的横距
	h = 80; #生成照片的竖距
	pixel = 20; #像素
    mode_split(savepath,modePath,(v,h),pixel)  #模板拼接

5.完整代码

完整代码如下:

import urllib,random, glob
from PIL import Image
import numpy as np
import cv2 as cv

savepath = '/home/zq/Documents/excample/pictures/'  #头像存储位置
resultSavePath = '/home/zq/Documents/excample/result.png'   #结果存储位置
modePath = '/home/zq/Documents/excample/mode.jpg'    #模板存储位置

path_picture_number = glob.glob(savepath + '*.jpg') #获取当前文件夹下pictures个数
# print(path_picture_number)
pictures_count = len(path_picture_number)   #picture数量
all_mean_rgbs = []   #存储计算出的所有平均rgb值

def meanrbg(img):  #计算图片平均rgb
    rgb = np.array(img)
    r = int(round(np.mean(rgb[:, :, 0])))
    g = int(round(np.mean(rgb[:, :, 1])))
    b = int(round(np.mean(rgb[:, :, 2])))
    return (r,g,b)

def savaImg(picurl,saveurl):  #存储图片函数,picurl是图片的URL,saveurl是本地存储位置
    try:
        bytes = urllib.request.urlopen(picurl)
        file = open(saveurl,'wb')
        file.write(bytes.read())
        file.flush()
        file.close()
        return True
    except:
        print('worry')
        savaImg(picurl,saveurl)

def mode_split(filepackage,modepath,bigsize,littlesize):  #以模板存储头像
    row = bigsize[0] #大图每行多少个小头像
    col = bigsize[1] #每列
    suitSize = (littlesize*row,littlesize*col)  #大图最终的像素size
    bigImg = Image.open(modepath)
    bigImg = bigImg.resize(suitSize)
    resultImg = Image.new('RGBA',suitSize)

    for i in range(row):
        for j in range(col):
            cutbox = (i*littlesize,j*littlesize,(i+1)*littlesize,(j+1)*littlesize)  #模板剪切用于对比的某个区域
            cutImg = bigImg.crop(cutbox) #复制到cutImg中
            tmprgb = meanrbg(cutImg)
            suitOne = mostSuitImg(tmprgb) + 1  #对比出最合适的头像

            img = Image.open(filepackage + str(suitOne) + '.jpg').convert('RGBA')
            img = img.resize((littlesize,littlesize))
            resultImg.paste(img,cutbox)
            print('已粘贴',cutbox)

    resultImg.save(resultSavePath)  #存储

def mostSuitImg(tmprgb):  #进行对比,找出最合适的头像
    global all_mean_rgbs
    minRange = 200000
    id = 0
    for rgb in all_mean_rgbs:
        tmp = (rgb[1][0]-tmprgb[2])**2+(rgb[1][1]-tmprgb[1])**2+(rgb[1][2]-tmprgb[1])**2
        if tmp<minRange:
            minRange = tmp
            id = rgb[0]
    return id


if __name__ == '__main__':
    #存放匹配图片 rgb 信息
    for i in range(1,pictures_count + 1):
        img = cv.imread(savepath+str(i)+'.jpg')
        rgb = meanrbg(img)
        all_mean_rgbs.append(rgb)
    all_mean_rgbs = list(enumerate(all_mean_rgbs))  #给列表增加一个索引

    v = 60; #生成照片的横距
	h = 80; #生成照片的竖距
	# 注意这里的 v,h 比值最好为模板照片的比例,这里为 3 :4
	pixel = 20; #像素,越高效果越好,但费时
    mode_split(savepath,modePath,(v,h),pixel)  #模板拼接

运行结果

运行上述代码,运行界面截图如下:

在这里插入图片描述
待运行结束,生成图片效果如前言所示。


总结

用 Python 生成的效果和其他专业的 P图软件比起来自然是没得说,但是其强在自动化与并不需要过强的专业技术,作者也是 Python 刚入门,代码中有不足还请各位大佬们评论区指正,觉得有帮助可以收藏点赞加关注,谢谢亲们支持!


本文属作者原创,转载请注明出处:
https://blog.csdn.net/weixin_46584887/article/details/117718969

以上是关于情人节要到了,为你的女友拼一张照片墙吧!的主要内容,如果未能解决你的问题,请参考以下文章

❤️❤️❤️情人节必备,和女友一起玩新版飞机大战!万字只为你❤️❤️❤️收藏起来吧

女友半夜加班发自拍 python男友用30行代码发现惊天秘密

女友半夜加班发自拍 python男友用30行代码发现惊天秘密

七夕节要到了,你的钱袋子还好吗?

情人节来了,一款让程序员男友记住一辈子的 IntelliJ IDEA 神仙插件。。

一张半夜加班发自拍 python小哥 30行代码发现惊天秘密