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 Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、