社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

使用四叉树算法在Python中实现照片样式器

Python程序员 • 5 年前 • 526 次点击  

了解如何编写python脚本以创建用于设置照片样式的基于四叉树的过滤器

 

所以最近,我发现了一个由 Michael Fogleman 完成的名为 四叉树艺术(QuadTree Art)的项目。它启发我尝试编写该项目的个人版本。这就是我将在本文中讨论的内容,如何实现你自己的四叉树艺术程序,正如我在这里所做的:github.com/ribab/quadart

上面是我用 kstudio 根据在 freepik.com 上找到的一张苹果图片生成的图像。原图如下:

只有当颜色的标准差太大时,我的算法才会继续将图像分成四分之一。

为了说明算法的工作原理,我为QuadArt实现了最大递归特性,使用这个shell命令创建了10个不同递归深度的图像: 

for i in {1..10}; do ./quadart.py apple.jpg -o r-out/apple-r$i.jpg -m $i --thresh 25; done

然后我通过这个命令用ImageMagick生成了这个 PNG 

convert -delay 40 -loop 0 *.jpg apple-r.gif

下面是GIF,动态展示了quadart魔法。


简单说说 QuadArt 算法


尽管我的程序 QuadArt 占用了181行代码,但用于生成Quadart的实际递归算法只需要8行就能描述。

上面的算法是直接从我的代码中提取出来的。class QuadArt 是包含 imageio 图像数据、 wand 绘制画布和标准差阈值的类。x, y, w, h被传递到函数中,以指定当前被分析子图像左上角的x,y位置,以及它的宽度和高度。

调试慢速 QuadArt 生成


最初,我使用 Python Wand 模块实现了整个Quadart程序,该模块在底层使用 ImageMagick。这个库把圆渲染得很漂亮。在通过实现基于四叉树的照片过滤器的第一个步骤进行编码之后,我遇到了一个问题,代码处理时间太长。事实证明,让 Wand 检查每个像素的颜色对于计算标准差来说需要很长的时间,而且 Wand 没有执行这种分析的内置特性。另外,当屏幕上没有显示任何内容时,很难判断代码是否被卡住。


为了判断我的代码是否有任何进展,我需要某种类型的加载条。但是,使用迭代算法加载条形图要容易得多,当中,你可以精确地知道算法需要多少次迭代才能完成。使用基于四叉树的递归算法,我知道递归深度1最多运行4次,深度2最多运行16次,依此类推。因此,考虑到这个想法,我实现了一个算法的补充,当程序执行时在终端上显示一个加载条。此加载条跟踪递归算法在深度3处执行的次数。

这个加载条GIF是由zanz在xwininfo的帮助下生成的。


为了让加载条函数跟踪 recursive_draw()的进度,我只需要跟踪它的退出点,并跟踪当前的递归深度。这两种退出点是指什么时候 recursive_draw()进一步递归或没有递归。下面是被修改为调用 loading_bar()的 recursive_draw() 函数:

loading_bar() 的逻辑是只能在depth<=3时计算进度, 但我仍然需要检查在 recursive_draw() 的第一个退出点中当前 self.recurse_depth 是否等于3,否则由于递归,将有对loading_bar()多余的调用。


这就是 loading_bar() 的样子

为了监视你自己的递归函数,你可以很容易地将它放在python代码的顶部,将recursion_spread 修改为函数每次递归时调用自身的次数,然后从递归函数的所有端点调用loading_bar() ,确保在每个递归分支它只被调用一次。

用 imageio 和 numpy 进行图像分析


对于是否拆分为更多四分分支的 recursive_draw() 阈值,函数too_many_colors() 计算红色、绿色和蓝色的标准差,如果标准差超过阈值,则返回True。对于 Quadart 的生成,我发现一个不错的阈值大约是 25 标准差,否则图像会变得太像素化或太细。python图像分析库imageio非常适合这种分析,因为它可以直接插入numpy进行快速统计计算。


我通过 imageio 和 numpy 进行图像分析的初始设置如下:

  1. 导入 imageio 和 numpy

  2. 用 imageio 读取图像 (filename 是我们要分析的图像的名字)

  3. 选择我们要分析的图像的一部分。有效地修剪img。left, right, up, and down 指定裁剪img的位置。

  4. 查找图像宽度和高度

  5. 通过将长边减去短边的差,确保 img 是方形的。

  6. 现在 imageio 对象img可用于计算标准差,如下所示:

    1. 选择颜色

    2. 根据颜色计算平均值

    3. 根据颜色计算标准差

这就是我的程序 QuadArt 如何计算 recursive_draw() 函数是否会因颜色偏差过大而进一步递归。看一下 too_many_colors()

上面的函数是这样做的:

  1. 选择颜色

  2. 根据颜色计算平均值

  3. 若平均值非常接近白色,则立即返回 False

  4. 根据颜色计算标准差

  5. 若标准偏差大于任何颜色的阈值,则返回 True (进一步递归)

  6. 否则返回 False


最后显示圆


现在简单的部分:在 wand中显示圆。我执行图像过滤器的策略是从空白画布构建生成的图像。这是一个如何用 Wand 画东西的模板

生成的QuadArt画布的纵横比始终是方形的,这样 QuadArt 的递归算法可以将图像均匀地分割为四分之一。默认情况下,我使用output_size=512,因为512是2的幂次,可以连续二分,分为更多四分分支,而不会损失分辨率。

然而,输入图像的大小可能会有所不同。为了解决这个问题,我将所需的输出图大小除以裁切的输入图像的宽度,如下所示:

我在 recursive_draw() 中使用的函数是 draw_avg()。这是一个简单的函数,它计算输入图像在边界内的平均颜色,然后在盒子中绘制一个圆(绘制一个正方形,如果用户愿意)。 

函数 get_color() 首先获取输入图像的裁剪部分(以imageio格式),然后计算该裁剪部分中红色、绿色和蓝色的平均值,然后根据计算出的平均颜色创建wand.color.Color 对象。 

在已定义的盒子中绘制一个圆或一个正方形,这是前面由 too_many_colors() 计算得出的具有足够低偏差的四分分支。在绘制到画布之前,坐标连同宽度和高度乘以 output_scale。将 wand.drawing 的填充颜色设置为之前计算的平均颜色。然后将圆或正方形绘制到画布上。 

就是这样!这就是我如何实现四叉树照片样式器,以及你如何实现同样功能,或者是如何受到启发并创建自己的算法来样式化你的照片。


你可以在此处查看整个代码: github.com/ribab/quadart/blob/master/quadart.py



英文原文:http://www.codingwithricky.com/2019/08/03/1-quadtree-photo-stylizer-python/ 
译者:青书
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/38583
 
526 次点击