利用Java和photoShop实现照片拼图
概述
今天进行一个很有意思的实践,利用Java编程实现照片拼图,通过程序操作图片文件,结合photoshop软件,实现下面的效果:
![](/assets/blank.gif)
该图片由很多小图片拼接而成,放大以后是这样的效果:
![](/assets/blank.gif)
下文中将介绍实现步骤,主要用到了Java程序和photoshop,利用Java编程完成图片的拼接和原图像的采样,然后利用photoshop完成采样图片和拼图图片的叠加,达到更好的效果。
原理
构造这样一幅拼图的原理很简单,主要分为3个步骤:
① 将作为子元素的图片缩小,拼接成一幅图片,这里称为:拼图图片。
② 对原图片中的颜色进行采样,并实现图片的像素化,生成半透明的采样图片。
③ 将采样图片覆盖在拼图图片之上,操作完成。
合成步骤可以用下图来描述:
![](/assets/blank.gif)
利用Java中的BufferedImage类可以很轻松地对图片文件进行处理,在这里,我们主要的操作是:读取和写入图片中某个位置的像素值。主要用到的方法如下:
|
这里可以通过简单的计算来找到这些参 利用以上的API变可以完成图片的拼接操作。当然,这些API只是程序中的核心步骤,要编程生成拼图文件,还有很多问题需要解决,详见下文。
实现
接下来介绍具体的程序实现方式。
·参数设定
首先介绍程序中用到的几个参数:
|
这里可以通过简单的计算来找到这些参数之间的关系,如果设定了模板图片的尺寸(orgWidth、orgHeight)和元素图片(photoWidth、photoHeight)的尺寸以及放大倍率(L),此时,构成结果图片中的元素图片的行数和列数分别是:
column = floor[orgHeight / (photoHeight / L)]
这里的floor表示向下取整,即如果计算得到的行数和列数不是整数,此时,模板图片中的边缘部分可能无法呈现在结果图片中。同时,我们还可以计算出结果图片的大小尺寸:
resultWidth = orgWidth * L = row * photoWidth
resultHeight = orgHeight * L = column * photoHeight
该数据同时还是采样图片和拼图图片的大小尺寸数据。
以上为程序中用到的参数。
·调整长宽比例
调整长宽比例的目的是使得所有的元素图片具有相同的长宽比例,便于之后的程序调整图片的大小。在程序的输入中我们设定了元素图片的尺寸photoWidth、photoHeight,因此,元素图片的长宽比例为:photoWidth / photoHeight,将这个结果携程比值的形式为:
宽 :高 = w : h (其中:w = photoWidth / gcd, h = photoHeight / gcd)
其中:gcd为photoWidth和photoHeight的最大公约数。
在保证图片长宽比例的同时,我们还要使得修改后的图片的面积尽可能的大,这样就使得原有图片的内容能尽可能多地保留。
![](/assets/blank.gif)
这里需要计算两个参数:
qw = width / w;
qh = height / h;
其中:width和height为图片调整前的原始尺寸。 选择qw和qh的较小者q,然后就可以确定调整比例后的图片的尺寸(用width'和height'来表示):
width' = q * w
height' = q * h
此时,可以得到下面的结论:
qw > qh时,q = qh,此时:width' = qh * w, height' = height。
qw < qh时,q = qw,此时:width' = width, height' = qw * h。
·调整大小
调整比例后,所有的元素图片都有相同的长宽比例,接下来调整图片的大小。 调整图片大小的逻辑很简单,取出x坐标是width'/photoWidth的倍数,同时y坐标是height'/photoHeight的倍数位置的像素点即可。
·生成拼图图像
调整至所有元素图片大小相同后,我们就可以利用这些元素图片生成拼图图片了,拼图图片的大小为:resultWidth × resultHeight,元素图片的大小为photoWidth × photoHeight,拼图图片中具有row行,column列的元素图片。在这里,我们需要进行坐标映射,对于位于拼图图片的第r行第c列的元素图片,其中的任意一个像素点,如果该点在元素图片中的坐标是px,py,那么该点在拼图图片中的坐标dx,dy可以表示为:
dx = photoWidth * r + px
dy = photoHeight * c + py
其中:0 ≤ px < photoWidth, 0 ≤ py < photoHeight。
确定了元素图片和拼图图片的坐标映射关系后,我们还需要决定具体每个位置要选择哪个图片进行覆盖,我们需要找到色调和模板图片对应位置最相似的图片进行覆盖,例如,如果模板图像为一张人像,那么图片中人面部颜色较浅,我们需要选择颜色较浅的元素图片进行拼接;图片中头发的部分颜色较深,我们需要选择色调较暗的元素图片进行覆盖。
这里为找到每个位置的最合适的图片,我们定义一个判定的标准,在选择拼图图片中的第r行,第c列的位置的图片时,对于某一个候选图片中的每一个像素点(px,py),首先将其转化为拼图图片中的坐标(dx, dy),然后,在将其颜色和模板图片中对应为位置的像素点的颜色进行比较,计算其相似度s,对于相似度s,我们定义为两像素点红、绿、蓝三个分量的绝对差值之和,即:
r1 = rgb1 & 0x000000ff;
s = |r2 - r1| + |b2 - b1| + |g2 - g1|
然后将s值和约定的阈值s0进行比较,统计候选图片中s值小于阈值s0的像素点的个数count,找到候选图片中count值最大的图片,就是当前位置需要选择的图片。
这里还有一个问题:由于模板图像和拼图图像的大小是不相同的,因此,在比较像素点的相似度时,还需要对拼图图片的坐标和模板图片的像素点坐标进行坐标映射。通过计算,我们可以得到:对于拼图图像中的位置(dx,dy)原始图像中的对应位置(rx, ry)可以表示为:
rx = dx / L
ry = dy / L
进而,根据上文中的计算结果,我们可以得到元素图片中的像素点坐标(px,py)和模板图片中的坐标(rx, ry)之间的直接映射关系:
rx = orgWidth / row * r + px / L
ry = orgHeight / column * c + py / L
这样,在选择图片时,将位于元素图片中(px, py)位置的像素点和模板图片中位于(rx, ry)位置的像素点进行比较,计算相似度s,选择最优的图片拼接即可。
下图是笔者采用的模板图片和生成的拼图图片,可以看到,设定的放大倍率越大,包含的元素图片越多,生成的拼图图像和模板图像的相似度也就越高。
![]()
模板图片
|
![]()
拼图图片(L=2)
|
![]()
拼图图片(L=5)
|
![]()
拼图图片(L=10)
|
·生成采样图片
生成拼图图片过程中,虽然程序会通过计算找到合适元素图片对模板图片的每个位置进行拼接,但是,如果选择的元素图片在色彩上和模板图片差别很大,生成的拼图图像效果依旧不好,解决的方案是在拼图图像上覆盖一层半透明的基于模板图像的采样图像使得拼图图像的色调跟符合原图。本步骤的目的就是生成这个采样图片,显然采样图片的尺寸和拼图图片是完全一致的。
对于由row行column列元素图片构成的拼图图片,其对应的采样图片也由row行column列构成,不同的是,构成采样图片的每个元素图片是只有一种颜色的纯色色块,这里由于笔者对于计算机图形学的相关知识了解甚少,因此采用一种最简单的策略,选择模板图片对应位置的中心位置的像素的颜色作为采样色。如下图所示:
![](/assets/blank.gif)
同样,这里需要对模板图片和采样图片之间进行坐标映射,这个映射关系和上文中选择元素图片时用到的映射关系很相似,对于采样图片中第r行第c列的元素图片,其颜色应该采样于模板图片中的sx,xy位置,则:
sx = orgWidth / row * (r + 1/2)
sy = orgHeight / column * (c + 1/2)
![]()
模板图片
|
![]()
采样图片(L=2)
|
![]()
采样图片(L=5)
|
![]()
采样图片(L=10)
|
·代码整合
以上就是Java程序完成的全部工作,为了操作方便,笔者利用Swing绘制了GUI界面,将以上各个步骤的代码整合起来:
![](/assets/blank.gif)
PS叠加
最后的步骤是叠加,利用photoShop将采样图片叠加在拼图图片之上,然后将采样图片设置为半透明即可:
![](/assets/blank.gif)
以上便是生成照片拼图方法。
程序代码
程序代码见:https://github.com/octopusfly/photo_puzzle,有兴趣朋友可以体验一下。
利用Java和photoShop实现照片拼图相关推荐
- java读取网络图片数据_如何利用java读取网络照片
如何利用java读取网络照片 Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的`编程.以下是小编为大家搜索整理的如何利用java读取网络照片, ...
- 用Java实现的简易马赛克拼图
用Java实现的简易马赛克拼图 什么是马赛克拼图 效果图 原理 所有代码 什么是马赛克拼图 马赛克拼图 简单来说就是远远看上去是一张大图,放大之后会发现其实是由许多张不同的小图组成 效果图 如果准备的 ...
- 利用Java进行身份证正反面信息识别
利用Java进行身份证正反面信息识别 1.百度授权信息准备 首先你得在百度AI开放平台上面注册一个账号,或者已经有百度账号了,网址是:https://ai.baidu.com/,如下图所示: 然后点击 ...
- 照片拼图制作怎么弄?这几个方法或许能帮到你
过年的时候,跟几个相识多年的朋友出门去玩.期间,我们拍摄了许多照片准备用来发朋友圈.回到家后,看到她们因为微信的朋友圈只能上传九张照片而在讨论要用哪张照片的时候,我说出了那句至理名言"小孩子 ...
- 利用RAW格式处理大光比照片
从来只发处理过后的照片,对处理过程绝口不提,第一次尝试说说后期处理过程中的一些小技巧,就说说利用RAW格式处理大光比照片吧,这个技巧在这阵处理同学的婚纱照过程中就有用到. 背景知识 相机的宽容度就是相 ...
- 照片拼图软件哪个好?这几个软件好用且简单
最近我总是收到大家要怎么制作照片拼图的私信,看来大家拍了很多好看的照片呀.为了解决大家的问题,我马上就开始搜集资料了,在经过我一番尝试后,我觉得这三款软件不错.小伙伴们可以先收藏这篇文章呀,这样以后就 ...
- 手把手教你利用Java获取图片GPS信息
你知道的越多,不知道的就越多,业余的像一棵小草! 成功路上并不拥挤,因为坚持的人不多. 编辑:业余草 推荐:https://www.xttblog.com/?p=5251 一张图片能包含很多敏感信息, ...
- java 根据ip获取mac地址_利用java如何根据IP获取mac地址
利用java如何根据IP获取mac地址 发布时间:2020-11-25 15:49:42 来源:亿速云 阅读:74 作者:Leah 利用java如何根据IP获取mac地址?针对这个问题,这篇文章详细介 ...
- Oracle字符串转BooIean,利用Java的多线程技术实现数据库的访问.pdf
利用Java的多线程技术实现数据库的访问.pdf 第 卷第 期 计算机应用 22 12 Voi .22 , No . 12 年 月 2002 12 Computer Appiications Dec ...
- 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...
最新文章
- java泛型中?和T有什么区别?
- 报销流程不简单,OA平台的私人订制
- CVTE(WEB后台开发)
- C++ 基础概念、语法和易错点整理
- 【跃迁之路】【428天】程序员高效学习方法论探索系列(实验阶段185-2018.04.09)...
- 计算机技术题目,计算机技术题目.doc
- 转:springboot servlet使用配置
- JS_15作用域与作用域链
- 说说Javascript
- Visual Studio 2005 重置设置
- Excel/WPS之粘贴可见内容
- Python-从txt中获取所有带有书名号的内容,并去除重复内容
- 关于linux校准时间
- python 简单操作dbpedia
- 如何登录无线web认证服务器,路由器如何设置web认证的方式连接免费WIFI
- Python 多态,概念与示例,精简篇
- Arduino智能小车设计(二)
- 微信小程序 SOTER 生物认证DEMO,指纹识别
- Model 3 FBCM
- Linux环境编程05
热门文章
- 设定session.timeout=30后,可是不到5分钟session变量就消失了.为什么?
- 阅读笔记:XModal-ID: Through-Wall Person Identification from Candidate Video Footage Using WiFi
- ps裁剪和裁切的区别_PS剪切、裁剪、裁切的区别
- java实现角色+武器攻击小游戏
- 完爆面试官!2021Java高频精选面试题讲解
- Qt警告:Missing reference in range-for with non trivial type (QString) [clazy-range-loop]
- Unity中的存档与读档
- 笔记本电脑显示dns服务器出错,电脑出现dns错误无法上网的解决方法详解
- 【Excel】某列数据有效性根据另外一列数据有效性进行动态更改
- diskpart建立新卷