热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

千图成像_Python实现千图成像,祝小可爱们圣诞快乐

❝微信公众号:「Python干货铺子」关注即可开启快乐学习Python和Matlab的大门,您还在犹豫什么~❞前言当走上街头时能隐约察觉到多了些许“红白

微信公众号:「Python干货铺子」关注即可开启快乐学习Python和Matlab的大门,您还在犹豫什么~

前言

当走上街头时能隐约察觉到多了些许“红白绿”的色彩,那是:圣诞老人?、雪花❄️、圣诞树?。霓虹灯闪烁,各类促销活动海报琳琅满目。没有错,圣诞节快来了~

从写文章开始,一路上得到了不少小伙伴的支持和鼓励,而这周CSDN上的总排名不偏不倚,恰好100名整。我想,这大概是某种巧合,更确切来说应该是一种激励。近些日,严酷寒冬似乎柔情了许多,有了那么几日的柔柔暖阳,而我希望可以把这份温暖也带给大家。

我将用粉丝的头像拼接出一幅圣诞树,正所谓,“「千图成像,集万千之美」”。

一、?圣诞树?

6fb4c08eb62d5614b611476ac42ea22f.png

该图的像素为6200x10250,将其局部放大后的效果为:f44fc28b2467c810c4d278888aaf8aa9.png今天所用到的代码是比较「通用」的,只需要替换背景图和图片库即可打造属于你自己的专属图片。详情分析,客观您往下瞅瞅~

帅小伙!圣诞来袭,还不赶快用来表白一波,还在犹豫啥呢?

二、代码分析

1.头像爬取

通过爬虫将粉丝的头像下载到本地,具体分析大家可以参考我之前的博客【前方高能!看小伙是怎么表白粉丝的】,完整代码如下:

# -*- coding: utf-8 -*-
"""
Created on Sat Oct 17 12:27:33 2020
@author: kimol_love
"""

import requests

def get_fansInfo():
    '''
    获取粉丝相关信息
    '''
    url = 'https://me.csdn.net/api/relation/index?pageno=%d&pagesize=%d&relation_type=fans' # 接口地址
    COOKIEs = {} # CSDN登陆后的COOKIEs
    headers = {  # 请求头
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Referer': 'https://i.csdn.net/',
        'Origin': 'https://i.csdn.net',
        'Connection': 'keep-alive',
        'TE': 'Trailers',
    }
    # 获取粉丝总数
    res = requests.get(url%(1,10),headers=headers,COOKIEs=COOKIEs)
    res_json = res.json()
    N_fans = res_json['data']['data_all']
    print('一共有%d个粉丝'%N_fans)
    # 获取全部粉丝数据
    res = requests.get(url%(1,N_fans),headers=headers,COOKIEs=COOKIEs)
    res_json = res.json()
    return res_json

def download_avatar(username,url):
    '''
    下载用户头像
    '''
    savePath = './avatars' # 头像存储目录
    res = requests.get(url)
    with open('%s/%s.jpg'%(savePath,username),'wb') as f:
        f.write(res.content)
     

if __name__ == '__main__':
    fans = get_fansInfo()
    for f in fans['data']['list']:
        username = f['fans'] # 用户名
        url = f['avatar']    # 头像地址
        download_avatar(username,url)
        print('用户"%s"头像下载完成!'%username)

将头像下载完毕并去重,结果如下:cc70f72f8deab3d20d77ab95e229b0be.png一共有2796张非重复图片,有了它们,我们便可以开始——搞事情!

2.千图成像

所谓「千图成像」就是用很多张图片拼接成一张完整的图片,它需要两个部分:「一张背景图」,「一个图片库」。根据背景图的结构用图片库中的图片来进行拼接,最终形成新的图片。

一种最简单直观的思路便是:遍历背景图中的每个像素点,并用图库中与之颜色最相近的图片粘贴在这个位置。

因此,我们首先需要计算每个图片的“平均颜色”,即图片像素点(R,G,B)的平均值,代码如下:

def compute_mean(imgPath):
    '''
    计算平均(R,G,B)
    '''
    img = Image.open(imgPath)
    img = img.convert('RGB')
    imgArray = np.array(img)
    R = np.mean(imgArray[:,:,0])
    G = np.mean(imgArray[:,:,1])
    B = np.mean(imgArray[:,:,2])
    return (R,G,B)

遍历图片库中的每张图片,并得到它们的平均距离,生成一个图片列表,以便后续的使用:

def get_imgList(imgDir):
    '''
    获取图片列表(图片目录及平均颜色)
    '''
    imgList = []
    for imgName in os.listdir(imgDir):
        path = imgDir+imgName
        color = compute_mean(path)
        imgList.append({'path':path,'RGB':color})
    return imgList

该列表的每个元素是一个字典,包括了「path」「RGB」,分别表示图片的路径以及图片的平均颜色,如下:4f86a24511c73e157cf43762ba42bda9.png在得到了图片的“平均颜色”后,便是比较背景图的像素点与它的相似性,这里采用了欧式距离:

def compute_distance(color1, color2):
    '''
    计算两张图的颜色差
    '''
    dis = 0
    for i in range(len(color1)):
        dis += (color1[i]-color2[i])**2
    dis = dis**0.5
    return dis

剩下的便是遍历背景图,并进行比较填充,代码如下:

def create_image(bgImg,imgDir,N=10,M=50):
    '''
    根据背景图,用头像填充出新图
    bgImg:背景图地址
    imgDir:头像目录
    N:背景图缩放的倍率
    M:头像的大小(MxM)
    '''
    # 获取图片列表
    imgList = get_imgList(imgDir)
    
    # 读取背景图
    bg = Image.open(bgImg)
    bg = bg.resize((bg.size[0]//N,bg.size[1]//N)) # 缩放
    bgArray = np.array(bg)
    width = bg.size[0]*M  # 新生成图片的宽度
    height = bg.size[1]*M # 新生成图片的高度
    
    # 创建空白的新图
    newImg = Image.new('RGB',(width,height))
    
    # 循环填充图
    for x in range(bgArray.shape[0]):
        for y in range(bgArray.shape[1]):
            ## 找到距离最小的图片
            minDis = 10000
            index = 0
            for img in imgList:
                dis = compute_distance(img['RGB'],bgArray[x][y])
                if dis                     index = img['path']
                    minDis = dis
            ## 填充
            tempImg = Image.open(index)
            tempImg = tempImg.resize((M,M))
            newImg.paste(tempImg,(y*M,x*M))
            print('(%d, %d)'%(x,y))
            
    # 保存图片
    newImg.save('千图成像.jpg')

调用它:

create_image('bg.jpg','./avatars(dr)/',5,50)

函数的输入有「bgImg」「imgDir」「N」「M」,它们分别表示:

参数含义
bgImg背景图的地址
imgDir图片库的目录
N背景图的压缩比率
M填充的图片大小

注:imgDir最后需要有目录连接符/,否则会报错;N是为了将背景图的尺寸进行调整压缩,否则容易因为像素点太多而执行缓慢。

最后,代码一Run,小图在手,简单的快乐,美滋滋~

写在最后

客观来说,该代码的执行效率并不高,特别是当N设置得较小(即背景图片像素点很多)或者图片库中的图片很多时。针对这个问题,也有很多优化方法,例如采用图片向量的方式对图片进行编码,进而比较等等。感兴趣的小伙伴可以参考这篇文章。如果需要完整代码,请在后台回复「千图成像」即可领取~

最后,祝愿最可爱的小伙伴们圣诞快乐?,愿我们聚于一图,焕尽万丈芒!另祝即将奔赴考研战场的小伙伴「考的都会,会的都考」!

我是kimol君,咋们下次再会~3876059238ef38088759842836cd0d3d.png创作不易,大侠请留步… 动起可爱的双手,来波点赞关注再走呗 (๑◕ܫ←๑)




推荐阅读
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 我正在尝试使用scrapycrallsingle运行完美运行的scrapy蜘蛛,但我无法在python脚本中运行它.主要问题是从不执行SingleBlogSpider.parse方 ... [详细]
  • win10清理电脑垃圾 ... [详细]
  • \\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*if(string.IsNullOrEmpty(Tex ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
  • AFNetworking、MKNetworkKit和ASIHTTPRequest比较
    2019独角兽企业重金招聘Python工程师标准之前一直在使用ASIHTTPRequest作为网络库,但是由于其停止更新,iOS7上可能出现更多的 ... [详细]
author-avatar
最佳永恒的六二
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有