五一劳动节,首先祝所有的劳动者节日快乐,向奋战在劳动的抗疫战士致敬。本想出去走一走,无奈人太多,就不给景区增加负担。
之前有一些文章陆续进行了全景照片的处理说明。之前的文章链接,1、实战!使用pano2vr生成html5全景页面 2、基于Three.js的全景展示框架-TPano 3、全景自动切片技术-krpano初识。本次分享一个比较真实的全景处理案例,可以自动完成全景照片的切片及展示场景需求。
环境说明:
1、JDK8、MySQL5.7、SpringBoot、Hibernate、krpano-1.19-pr13、Thymeleaf、JQuery3.4.1、Bootstrap3.3.7
下面正式进入正题。
第一步、项目Pom.xml定义
如下代码所示:
<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.0.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><groupId>cn.com.scitc</groupId><artifactId>pano</artifactId><version>1</version><packaging>war</packaging><name>pano</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency></dependencies></project>
第二步、安装krpano
具体步骤可参见krpano的官网或者网络教程。这里不进行赘述。在服务器上执行脚本命令行完成切片的功能。核心代码结构截图如下:
在controller中定义了所有的页面交互控制类。每个控制类根据命令已经大致可以猜到具体的用途。文中核心的转换逻辑写在PageController中,核心代码如下:
// 执行上传"/upload") (publicStringupload( ("file") MultipartFilefile, Modelmodel) throwsIOException { //获取用户名UserDetailsuserDetails= (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Stringname=userDetails.getUsername(); // 获取上传文件名Stringfilename=file.getOriginalFilename(); StringfileName=filename.substring(0,filename.length() -5); // 定义上传文件保存路径Stringpath=filePath+"rotPhoto/"+name; // 新建文件Filefilepath=newFile(path, filename); // 判断路径是否存在,如果不存在就创建一个if (!filepath.getParentFile().exists()) { filepath.getParentFile().mkdirs(); } try { // 写入文件file.transferTo(newFile(path+File.separator+filename)); } catch (IOExceptione) { e.printStackTrace(); } // 将src路径发送至html页面model.addAttribute("filename", "/images/rotPhoto/"+name+"\\"+filename); Stringcmd; Stringappction="E:/krpano/krpano-1.19-pr13/krpanotools64.exe makepano -config=templates/vtour-normal.config D:/code/pano/src/main/resources/static/images/rotPhoto/"; cmd=appction+name+"/"+filename; try { Processprocess=Runtime.getRuntime().exec(cmd); InputStreamis=process.getInputStream(); InputStreamReaderisr=newInputStreamReader(is); BufferedReaderbr=newBufferedReader(isr); Stringcontent=br.readLine(); while (content!=null) { System.out.println(content); content=br.readLine(); } } catch (IOExceptione) { e.printStackTrace(); } String[] wenname=newString[4]; Stringpathfile="D:/code/pano/src/main/resources/static/images/rotPhoto/"; wenname[0] =pathfile+name+"/vtour/usergoods.html"; wenname[1] =pathfile+name+"/vtour/tour.swf"; wenname[2] =pathfile+name+"/vtour/tour_testingserver.exe"; wenname[3] =pathfile+name+"/vtour/tour_testingserver_macos"; for (inti=0; i<wenname.length; i++){ Filefilethree=newFile(wenname[i]); filethree.delete(); } // 删除生成的重复的文件包String[] wennametwo=newString[2]; wennametwo[0] =pathfile+name+"/vtour/plugins"; wennametwo[1] =pathfile+name+"/vtour/skin"; for (inti=0; i<wennametwo.length; i++){ Filefilefour=newFile(wennametwo[i]); DeleteFiledeleteFile=newDeleteFile(); deleteFile.deleteFile(filefour); } try { Patternpattern=Pattern.compile("<include url=\"skin/vtourskin.xml\" />", Pattern.CASE_INSENSITIVE); // 要匹配的字段内容,正则表达式Matchermatcher=pattern.matcher(""); List<String>lines=Files.readAllLines(Paths.get(pathfile+name+"/vtour/tour.xml")); // 读取文本文件for (inti=0; i<lines.size(); i++) { matcher.reset(lines.get(i)); if (matcher.find()) { // 匹配正则表达式lines.remove(i); lines.add(i, "<include url=\"../../../../skin/vtourskin.xml\" />"); } } Files.write(Paths.get(pathfile+name+"/vtour/tour.xml"), lines); } catch (IOExceptione) { e.printStackTrace(); } FileoldFile=newFile("D:/code/pano/src/main/resources/static/images/rotPhoto/"+name+"/vtour"); if(!oldFile.exists()){ oldFile.createNewFile(); } StringrootPath=oldFile.getParent(); FilenewFile=newFile(rootPath+File.separator+fileName); if (oldFile.renameTo(newFile)){ log.info("修改成功!"); }else{ log.info("修改失败"); } return"upload"; }
后台接收前台上传的文件后,即开始进行全景切图。
第三步、全景图片展示核心代码如下:
"/") (publicclassHomeController { privateLoglog=LogFactory.getLog(getClass()); "/include/navstyle") (publicStringnavstyle(){ return"/include/navstyle"; } "/select") (privateStringselect(Modelmodel) { UserDetailsuserDetails= (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Stringname=userDetails.getUsername(); Filefile=newFile("D:/code/pano/src/main/resources/static/images/rotPhoto/"+name); if (!file.exists()){ model.addAttribute("goods","/prompt"); }else { model.addAttribute("goods","/goods"); } if (!file.exists()){ model.addAttribute("works","/prompt"); }else { model.addAttribute("works","/userwork"); } return"select"; } "/include/nav") (privateStringnav() { return"/include/nav"; } "/include/footer") (privateStringfooter() { return"/include/footer"; } "/prompt") (privateStringprompt() { return"/prompt"; } }
最后我们来看下展示的效果。
首页展示
万里长城展示
全景处理
全景处理
总结:本文介绍了一种基于krpano的全自动处理平台,可以自动发布全景实战案例。完整构建了完整的生命周期,从图片上传,到后台图片切片等,基本具备服务能力。但是本平台也存在一定的缺点,比如:页面UI不够美观、不兼容Linux平台、没有采用文件存储模式、图片处理没有异步化,系统容错性不好、krpano的工作路径是固定的,没有设置成动态路径,于此同时,还有一些bug需要调整。
不过总体来说,是一个很好的全景处理程序,提供了比较详细的处理逻辑。有兴趣的朋友可以在此基础之上进行二次开发和扩展,比如去弥补上述的一些缺陷也是未尝不可以的。最后分享开源地址:https://gitee.com/hszzz/pano.git,有需要的小伙伴可以自行下载。