Python学习班微分享实录:用Python实现Mosaic Photo

2024-02-11 13:10

本文主要是介绍Python学习班微分享实录:用Python实现Mosaic Photo,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文基于CSDN Python学习班微分享内容整理,主要讲解了如何通过Python程序实现Mosaic Photo效果。主讲人陈舸,8年开发经验,曾就职华为、烽火通信,目前创业中。《Python Cookbook第三版》译者,《Linux/Unix系统编程手册 下卷》以及《算法精解 C语言描述》合作译者。点击这里下载程序源码

肯定有人会问什么是Mosaic Photo,那我们先来看一看最终的效果吧。

image

上图是在google上搜索的mosaic风格的图片。这种风格的图片都是由其它多张小图拼接而来的,最终形成了一张大图。我们可以在一些广告和海报上找到这种风格的设计。今天分享一个用Python写的程序,帮我们实现这种效果。

我们选了一张《越狱》的海报作为目标图片。最后我们会用多张图片拼接实现一张mosaic风格的海报,如下图所示。


我们可以在网上随机搜索100张图片作为拼接的素材。这些素材图不求高像素,但求随机。我们这次下载的素材图最大也不过几十KB。

首先,我们需要将目标图片分解为大小相等的block。同时,我们将素材图批量剪裁成与block大小相等的方形小图,在这里我们称之为tile。我们只要选取“合适”的tile像贴墙砖一样贴到block上,就可以得到最终的Mosaic海报了。

过程听起来很简单,但其中有两个核心问题:
1. 什么叫“合适”?
2. 怎么确定哪个tile贴到哪个block上?

先解决第一个问题。所谓“合适”,就是指我们选取的tile和要被贴的block在颜色上看起来最接近。目标图被划分成无数个block之后,有的区域颜色比较明亮,有的则偏暗,而我们手里的tile素材图更是五花八门,需要有一种方法能在众多的tile里选择出一个颜色与对应block最相近的,那这个“合适”与否也就可以确定了。

在对比颜色之前,我们先简单说明一下像素相关知识。

像素pixel,可简单看做(R,G,B)3维向量。因此要比对出颜色最接近的tile,其实就是去比对像素的差异。两个像素间的差异就是3维向量之间的距离,距离越小表示越接近也就越相似。那我们怎么求这个距离?

一维的求解:sqrt((x-y)^2) == | x – y|

二维的求解:sqrt((x1-x2)^2 + (y1-y2)^2)

三维的求解:sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2)

以此类推,我们可以将其扩展至n维。我们可以采用此方法,针对每个block,找到整体像素差异最小的那个tile,即为“合适”。

第二个问题,怎么知道哪个tile要贴到哪个block上?

当我们把原图划分成block后,其实每个block就有了一个坐标,用来确定这个block在目标图中的位置。而我们贴图用的资源tiles,可以全部读取到python的list中去,因此tile就有了下标索引。有了坐标,有了索引,就可以建立tile与block的对应关系。

到这里,我们已经解决了两个核心的问题。至于如何贴图、缩放、改变图片大小,我们就可以交给PIL库帮助我们解决。
大家在PIL库的网站可下载适用于Python 2.x 的PIL库,Python 3则可使用Pillow。

解题思路已经敲定,开始coding!

从上述代码可以看到,首先导入我们用的库,然后定义一些全局变量。

TILE_SIZE       = 3  

由于我们划分的block是 3x3 的大小,因此tile的大小也是 3x3 。

ENLARGEMENT     = 1  

第7行代码表示我们对目标图的放大倍数是1。如果设置成其他值,比如2,那么 300x200 的目标图,最后产生的结果将是 600x400。

EOQ_VALUE       = None

这个变量用来通知工作进程结束,我们在后面会详解。

下面开始编写class代码。

TileProcessor类就是用来处理我们的贴图素材tile的。init方法是接受传入的图片文件夹的路径。用get_tiles遍历目录中所有的图片,做一下裁剪后放入list。具体裁剪成方形的代码在22-27行。对于非正方形的tile,我们裁剪出正中心的方形区域作为备选的tile。

接下来我们看看TargetImage类,如下图代码所示。

TargetImage类用来处理我们的目标图,代码应该很好理解。在64行有一个if判断。因为我不希望贴图的时候出现最后还差半个或非整数个block,因此如果有这种情况,那我把原图也稍微做下裁剪,使得每行和每列要贴的block都是整数个。

如上图所示,在TileFilter这个类中,我们来确定哪个tile是“合适”的。其中,第84行的diff累加,就是之前我们说的计算3维向量的距离。get_best_fit_tile方法会返回最合适的那个tile所在的下标。此前,我们把所有tiles都裁剪为方形后存在list中。

如上图所示,MosaicImage类就是我们用来贴tile的类。初始化方法里我们根据目标图,按比例先生成一张底图,tile就是贴在这个底图之上。

除此之外,还有帮助类ProgressCounter,告诉我们贴图进度。在这里我们不赘述,大家可以下载源码查看,注释得很清楚。

接下来,我们还需要一些函数,将这些类串联起来。首先,我们来看compose函数。它非常关键,当我们拿到目标图的数据和tiles的数据后,就是调用它来完成后面的工作的,也就是合成拼图。

这里我们用了多进程,加速处理最佳tile匹配。可以看到,compose函数里起了几个新进程,有的用来处理tile匹配,有的用来贴图,通过队列queue来传递数据。因此,我们还写了一个 build_mosaic 函数(如下图所示),这个就是贴图进程所调用的函数。而最佳tile匹配就由 fit_tiles 函数(如下图所示)来完成。

最后,我们写一个main,让程序跑起来,我们看一下最终实现的效果。


希望加入Python 学习班?

请扫群主二维码,注明“Python”

这篇关于Python学习班微分享实录:用Python实现Mosaic Photo的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/699867

相关文章

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函