最近很火的全景圖功能是如何實現的?

2021-02-15 鴻洋

作者:張鵬輝_道長

連結:http://www.jianshu.com/p/adfab8201660

本文由作者投稿發布。

最近微博上的全景圖火了,所以決定實現一下。
工程裡面圖片資源來自網絡,如有侵權請聯繫我,馬上刪除
當然實現的方式很多比如OpenCV、u3d等。

這裡提供三種方式實現:

OpenGL ES

GoogleCardboard(Google VR)上面的一個集成模塊,我們只使用裡面展示全景圖部分模塊

Three.js(利用前端姿勢)WebView混合開發

三種姿勢孰強孰弱,根據需求你們自己判斷!我會在結尾給出一些建議,多說無益開擼。

先看下三種實現的效果:

1.OpenGL ES (實現後的效果故宮全景)

2.Google VR(全景圖模塊)

3.Three.js(利用前端姿勢)WebView混合開發

第一種方式使用OpenGL來實現(上面gif圖截取因為博客限制上傳圖片的大小,我壓縮了,看起來有些卡其實很流暢的)

可以看到支持旋轉手機查看、或者拖動圖片查看、可以看到右邊中心部分有個指示器會隨著角度變化而變化並且點擊可以還原起始位置。


一.使用

有些小夥伴懶得看原理,直接就想拿來用所以我先說集成方式吧!


Step 1

在build.gradle 文件中添加庫依賴:

allprojects {    repositories {        maven { url 'https://jitpack.io' }    }}


Step 2.Add the dependency

在 build.gradle 文件中添加庫依賴:

dependencies {    compile 'com.github.CN-ZPH:weibo360panorama:v1.0.1'}

Step 3.創建布局文件.XML

<com.zph.glpanorama.GLPanorama    android:id="@+id/mGLPanorama"    android:layout_width="match_parent"    android:layout_height="match_parent"></com.zph.glpanorama.GLPanorama>


Step 4.傳入你的全景圖

*R.drawable.imggugong  這張全景圖傳到控制項裡面

OK現在你可以測試玩玩了(別用模擬器玩咔咔報錯就來找我)。
二.分析

首先我們需要了解全景圖是什麼東西,全景圖是一種廣角圖。通過全景播放器可以讓觀看者身臨其境地進入到全景圖所記錄的場景中去,通常標準的全景圖是一張2:1的圖像,其背後的實質就是等距圓柱投影。


等距圓柱投影是一種將球體上的各個點投影到圓柱體的側面上的一種投影方式,投影完之後再將它展開就是一張2:1的長方形的圖像。比較常見的就是應用在地圖上的投影。

--引用慕課的一張介紹圖--

得到全景圖後那我們就需要展示了,看到旁邊地球了嗎?

怎麼展示呢簡單來說就是把全景圖片整個貼到一個球體上。


好了知道原理那我們就該考慮在android上怎麼實現了,在android中繪製3d圖形可以使用OpenGL (就不說OpenGL 基礎了想看的自己百度一大堆資料)。

1.繪製球體:

引用tim_shadow大佬的關於全景圖一篇文章介紹

原文:http://blog.csdn.net/tim_shadow/article/details/11890947

在OpenGL ES中基本上所有的立體圖像都是通過一個個的小三角形拼接而成我們知道球面上面的每一個點(P(x,y,z))都會滿足方程組(球的極坐標方程):
x = r * sin(a) cos(b)
y = r * cos(a)
z = r * sin(a)sin(b)
其中 r為球的半徑,a為線段 OP與 z軸正方向所夾角,b為 OP在xoy平面的投影 OP『 與x的正方向所夾角

--tim_shadow大佬的示意圖--


我們可以根據這個方程組,通過控制∠a和∠b的變化,從上到下,逆時針的取得我們需要用來組合稱三角形的點,然後我們需要將全景圖片上的點與我們在球上面選取的點一一對應起來(注意:球的坐標是3維坐標,圖片的坐標是2維坐標)
球上面的點與圖片上面的點一一對應起來。

紋理和圖片綁定繪製到屏幕上

2.利用傳感器讓球隨著手機轉動而轉動

第一想到的就是重力感應傳感器,可是只能獲得我們向那個位置偏移的方向,顯然不可能滿足我們旋轉的需求,使用陀螺儀傳感器。


陀螺儀就是內部有一個陀螺,它的軸由於陀螺效應始終與初始方向平行,這樣就可以通過與初始方向的偏差計算出實際方向。


陀螺儀對設備旋轉角度的檢測是瞬時的而且是非常精確的。


1.註冊陀螺儀傳感器

首先註冊陀螺儀傳感器根據具體需要自己設置靈敏度,當然越靈敏,越耗電。

註冊陀螺儀傳感器,並設定傳感器向應用中輸出的時間間隔類型是SensorManager.SENSOR_DELAY_GAME(20000微秒)

SensorManager.SENSOR_DELAY_FASTEST(0微秒):最快。最低延遲,一般不是特別敏感的處理不推薦使用,該模式可能在成手機電力大量消耗,由於傳遞的為原始數據,算法不處理好會影響遊戲邏輯和UI的性能

SensorManager.SENSOR_DELAY_GAME(20000微秒):遊戲。遊戲延遲,一般絕大多數的實時性較高的遊戲都是用該級別

SensorManager.SENSOR_DELAY_NORMAL(200000微秒):普通。標準延時,對於一般的益智類或EASY級別的遊戲可以使用,但過低的採樣率可能對一些賽車類遊戲有跳幀現象

SensorManager.SENSOR_DELAY_UI(60000微秒):用戶界面。一般對於屏幕方向自動旋轉使用,相對節省電能和邏輯處理,一般遊戲開發中不使用

我這裡為了測試設置了SENSOR_DELAY_FASTEST,實際使用建議用SENSOR_DELAY_GAME。

2.獲得傳感器數據


當傳感器的值發生變化時,例如磁阻傳感器方向改變時會調用OnSensorChanged(). 當傳感器的精度發生變化時會調用OnAccuracyChanged()方法。

從 x、y、z 軸的正向位置觀看處於原始方位的設備,如果設備逆時針旋轉,將會收到正值;否則,為負值。
得到兩次檢測到手機旋轉的時間差(納秒),並將其轉化為秒。
將手機在各個軸上的旋轉角度相加,即可得到當前位置相對於初始位置的旋轉弧度,將弧度轉化為角度。

3.設置填充球的Y,X的角度


每次獲得角度數據後只需要y,x的值計算位移的值

因為全景圖上下旋轉會翻轉整個圖所以我這裡設置了上下只能偏移50f,如果不限制你可以去掉

mBall.yAngle += dx* 2.0f;這裡*2.0也就是陀螺儀傳過來的值乘以得出偏移的角度,數值越大,每次偏移更快!


3.加入手勢操控,拖動圖片轉動


加入手勢這裡沒什麼好說的了,就是重寫onTouchEvent()方法。
這裡唯一要注意的就是,當手指點擊屏幕的時候要關閉陀螺儀傳感器的監聽不然會引起衝突。當手指離開屏幕,重新監聽陀螺儀傳感器。


和上面也一樣只是這裡換成獲取手指偏移角度,而不是傳感器的數值,直接看代碼。

4.加入指示器


指示器這裡弄了一個角標指示當前在全景圖的角度,並且點擊還原起始角度。
可以想像同樣是獲取角度,我們直接放在全景圖改變的地方,讓指示器一起改變,而我們改變的地方只有2個陀螺儀和拖動屏幕。

我這裡指示器放了一張圖也就是一個 ImageView 控制項:

--原圖為背景透明--

1.為指示器加入動畫跟隨全景圖一起轉

2.點擊指示器還原起始位置

當點擊還原的時候,我一開始是直接恢復起始位置可是太生硬了,通過獲取當前旋轉的角度,逆向旋轉,慢慢還原,讓其有個過渡的效果。
Y軸=旋轉的角度-90f(起始角度)/10f(每次偏移多少,經過我多次嘗試10f在我的手機上剛剛好);
得到我們總共偏移幾次可以復位;
X軸同理,因為我上面限制了X軸的最大偏移,這裡就不就算X軸了,不過在完成的同時直接復位X軸。(只是沒有過渡的效果),你可以加上。
我設置的起始角度是90f和0f,也就是X,Y軸的起始點
mHandlers.postDelayed(this, 16);
這行代碼就是多少毫秒復位一次。

看代碼:

至此第一種OpenGL ES方式核心代碼分析完畢,有不明白的地方可以找我。

第二種也就是谷歌官方為移動平臺下VR解決方案,有興趣的可以點開下面連結玩玩,我們只使用其中全景圖模塊。

Google VR主頁:

https://developers.google.com/vr/
Google VR for Android github地址:

https://github.com/googlevr/gvr-android-sdk


一.使用Step 1.Add the dependency

目前GitHub上最新版本號為1.8.0,我這裡也用最新的了。
最低支持到  minSdkVersion 19 也就是Android 4.4.0


在 build.gradle 文件中添加庫依賴:

dependencies {   compile 'com.google.vr:sdk-panowidget:1.80.0'}


Step 2.創建布局文件.XML


<com.google.vr.sdk.widgets.pano.VrPanoramaView    android:id="@+id/mVrPanoramaView"    android:layout_width="match_parent"    android:layout_height="250dip"/>

Step 3.AndroidManifest中添加權限

Step 4.Activity中初始化組件

第二種到這裡已經可以顯示玩玩了,也沒什麼可分析的,都是官方提供的sdk,會調用相關的方法就好了,具體都有那些方法接口,最好的文檔永遠都是官方提供的,上面已經給出了連結,最好自己把GitHub上的官方提供的demo拿下來跑一遍,我就不多介紹了。Three.js(利用前端姿勢)WebView混合開發

Three.js是JavaScript編寫的WebGL第三方庫。提供了非常多的3D顯示功能。

Android下相信很多人都多少做過前端開發,現在很多應用程式都是基於前端H5/RN/小程序等來玩的。


當然我們全景圖也可以放到前端來實現,套個WebView利用JavaScript與Android交互來實現一部分功能。

考慮到在多種機型兼容性,還有原生WebView的一些坑,我這裡使用騰訊的X5內核的WebView。


一.使用Step 1.添加x5 SDK

到x5官網下載最新的sdk得到一個jar包
我在這的是3.3.0版本的。


將下載好的jar包放到你的工程libs目錄下
在 build.gradle 文件中添加庫依賴:

dependencies {    compile files('libs/tbs_sdk_thirdapp_v3.3.0.1045_43300        _sharewithdownload_withoutGame_obfs_20170605_170212.jar')}


Step 2.AndroidManifest.xml裡加入權限聲明

Step 3.APPAplication中X5內核初始化


Step 4..創建布局文件.XML


<com.tencent.smtt.sdk.WebView        android:id="@+id/web"        android:layout_width="match_parent"        android:layout_height="match_parent"></com.tencent.smtt.sdk.WebView>

Step 5.下載Three.js

下載地址:https://threejs.org/
或者去GitHub從我的項目中找今天代碼都會放到GitHub上


<script src="js/three.min.js"></script><script src="js/photo-sphere-viewer.min.js"></script>


Step 6.編寫HTML文件

在 assets 目錄下創建一個html文件展示全景圖
引入Threejs
panorama:'https://gw.alicdn.com/tfs/TB1WSInRFXXXXXlXpXXXXXXXXXX-1200-600.jpg', 這行就是你的全景圖地址

你可以使用js交互將你的地址傳到HTML上

直接上代碼了:


Step 7.Activity調用HTML

很簡單就是把系統的WebView換成Tencent_Webview其他類似

最後附上插件的可配置參數:

panorama:必填參數,全景圖的路徑。

container:必填參數,放置全景圖的div元素。

autoload:可選,默認值為true,true為自動調用全景圖,false為在後面加載全景圖(通過.load()方法)。

usexmpdata:可選,默認值為true,如果Photo Sphere Viewer必須讀入XMP數據則為true。

default_position:可選,默認值為{},定義默認的位置,及用戶看見的第一個點,例如:{long: Math.PI, lat: Math.PI/2}。

min_fov:可選,默認值為30,觀察的最小區域,單位degrees,在1-179之間。

max_fov:可選,默認值為90,觀察的最大區域,單位degrees,在1-179之間。

allow_user_interactions:可選,默認值為true,設置為false則禁止用戶和全景圖交互(導航條不可用)。

tilt_up_max:可選,默認值為Math.PI/2,向上傾斜的最大角度,單位radians。

tilt_down_max:可選,默認值為Math.PI/2,向下傾斜的最大角度,單位radians。

zoom_level:可選,默認值為0,默認的縮放級別,值在0-100之間。

long_offset:可選,默認值為PI/360,mouse/touch移動時每像素經過的經度值。

lat_offset:可選,默認值為PI/180,mouse/touch移動時每像素經過的緯度值。

time_anim:可選,默認值為2000,全景圖在time_anim毫秒後會自動進行動畫。(設置為false禁用它)

theta_offset:過時的選項,可選,默認值為1440,自動動畫時水平方向的速度。

anim_speed:可選,默認值為2rpm,動畫的速度,每秒/分鐘多少radians/degrees/revolutions。

navbar:可選值,默認為false。顯示導航條。

navbar_style:可選值,默認為{}。導航條的自定義樣式。下面是可用的樣式列表:

backgroundColor:導航條的背景顏色,默認值為rgba(61, 61, 61, 0.5)。

buttonsColor:按鈕的前景顏色,默認值為transparent。

activeButtonsBackgroundColor:按鈕激活狀態的背景顏色,默認值為rgba(255, 255, 255, 0.1)。

buttonsHeight:按鈕的高度,單位像素,默認值為20。

autorotateThickness:autorotate圖標的厚度,單位像素,默認值為1。

zoomRangeWidth:縮放的範圍,單位顯示,默認值50。

zoomRangeThickness:縮放的範圍的厚度,單位像素,默認值1。

zoomRangeDisk:縮放範圍的圓盤直徑,單位像素,默認值為7。

fullscreenRatio:全屏圖標的比例,默認值為3/4。

fullscreenThickness:全屏圖標的厚度,單位像素,默認值為2。

loading_msg:可選,默認值為Loading…,圖片加載時的提示文字。

loading_img:可選,默認值為null,在加載時顯示的圖片的路徑。

size:可選,默認值null,全景圖容器的最終尺寸。例如:{width: 500, height: 300}。

onready:可選值,默認值為null。當全景圖準備就緒並且第一張圖片顯示時的回調函數。

總結

三種方式都實現完了,不用擔心今天所有代碼都會放在GitHub上。
三種方式具體你使用哪種我還是沒有推薦的
這裡只是一張圖,你可以多張圖實現來完成簡單的全景街景功能!點擊圖片某個區域,跳轉到下一個街景的圖,包括百度地圖裡面也是一張張全景圖拼接而成。

第一種我會在後續繼續完善加入更多的可選參數,你們有興趣也可以自己優化。

第二種是谷歌VR模塊的沒什麼好說的,畢竟官方倆字就夠了。

第三種跨平臺最好的,畢竟是個網頁。而我們第三種使用了騰訊X5內核來玩,但是還可以在優化,消耗不小,我建議你單獨給WebView分配一個進程和你的業務分離。

拿著我的保溫杯,泡一杯枸杞,我們下篇文章再會


項目源碼下載地址:

https://github.com/CN-ZPH/

覺得不錯請點一個star蛤!

如果你有想學習的文章直接留言,我會整理徵稿。如果你有好的文章想和大家分享歡迎投稿,直接向我投遞文章連結即可。

歡迎長按下圖->識別圖中二維碼或者掃一掃關注我的公眾號:

相關焦點

  • 最近很火的教程-如何在QQ空間發布360全景圖片
    最近有很多小夥伴看到別人空間裡發了各種360全景圖,覺得很炫酷,但是不知道怎麼發,今天嘟嘟教大家從下載和拍攝圖片到發送到自己空間裡的方法。微博從去年就支持上傳和瀏覽360全景圖了,上面有很多大佬用專業設備拍攝並製作的優秀全景圖。比較有名的博主是:全景相片、AirPano、720yun全景社區。當然,大家也可以自己搜索
  • 如何使用「照片合併」功能創建 HDR 全景圖
    今天小編帶大家了解如何使用「照片合併」功能創建 HDR 全景圖。
  • 360度全景圖如何製作?3D全景效果圖製作教程
    我們通常所說的360度全景圖大多數都是指3D全景效果圖,那麼360度全景圖
  • 如何用手機拍攝製作360全景圖??
    最近,QQ和微博裡的360全景圖火的一塌糊塗。看到360度的美景真的是讓人著迷啊!
  • 【教程】國外最火全景製作軟體
    現在,任何人只要有一部智慧型手機,便可以隨時地拍攝一張「全景照片」,但相比於專業的全景圖,手機拍攝的全景照片往往並不支持360°或720°全方位觀看。那麼,什麼才是真正全景圖呢?全景圖(panorama)是一種廣角圖,可以以畫作、照片、影片、三維模型的形式存在。全景圖這個詞最早由愛爾蘭畫家羅伯特·巴克提出,用以描述他創作的愛丁堡全景畫。
  • Android三種姿勢帶你玩轉360度全景圖功能
    最近微博上的全景圖火了,所以決定實現一下。        工程裡面圖片資源來自網絡,如有侵權請聯繫我,馬上刪除。當然實現的方式很多比如OpenCV、u3d等。二.分析        首先我們需要了解全景圖是什麼東西,全景圖是一種廣角圖。通過全景播放器可以讓觀看者身臨其境地進入到全景圖所記錄的場景中去,通常標準的全景圖是一張2:1的圖像,其背後的實質就是等距圓柱投影。等距圓柱投影是一種將球體上的各個點投影到圓柱體的側面上的一種投影方式,投影完之後再將它展開就是一張2:1的長方形的圖像。
  • OpenGLES和Swift實現全景圖瀏覽(全景球,360度瀏覽,小行星).md
    最近在學習 OpenGLES,其實也就學到紋理那裡,所以想著做個小項目來鞏固一下知識。而一個全景瀏覽器正好囊括頂點坐標,紋理坐標,索引繪圖,MVP 矩陣變換等等知識,是一個很不錯的練手項目。我選擇用 Swift 來寫,當然用 Swift 會相對麻煩一點,特別是在處理指針方面。
  • 【App】得圖全景相機
    比如ios自帶的全景相機,簡單的一掃就能拍攝去一張環形全景圖片,可惜是這不是真正意義上的全景照片,今天就為大家推薦一款真正意義的360度無死角全景相機應用-得圖全景相機。目前該app在官方商店已更新至1.2的版本,該有個功能都有了,可玩性較高。
  • 回顧好用的全景圖拼接軟體
    全景圖也帶來了一些挑戰。其中包括如何拍攝多張圖像並將它們縫合在一起成為一張全景圖像。一些較新的相機和智慧型手機內置了自動全景設置。它們使您可以圍繞視圖掃視相機,並將其全部縫合在相機中。但是就那樣方便,您通常對最終產品沒有太多控制權,並且解析度通常比相機通常的功能要低得多。
  • 銀河系全景圖
    就在去年,美國航天局公布了一張銀河系全景圖,雖然說是由200萬張照片拼接而成,不過當浩瀚無垠的銀河系圖片完整的出現時,那種絕美大氣依舊震驚了全世界。銀河系全景圖概述:去年,美國航天局公布了一張銀河系360°全景圖,該全景圖像素高達200億,是由斯皮策太空望遠鏡在過去10年拍攝的200萬張照片所拼接而成的。
  • Enscape 系列教學17:如何利用Enscape創建和分享全景圖
    在之前的紫天 Enscape 系列教學視頻中,我們曾經講解過如何使用 Enscape 創建全景圖,以及如何通過二維碼分享成果。
  • Google是如何提供「無縫」的街景全景圖的?
    文 / Google 軟體工程師 Mike Krainin、機器感知研究員 Ce Liu2007 年,我們推出了 Google 街景,它讓您可以從自己的瀏覽器或行動裝置通過街區、地標和博物館等的全景圖探索世界。這些全景圖的創建是一個複雜的過程,其中涉及從一個名為 Rosette 的多攝像頭平臺捕獲圖像,然後使用圖像混合技術將這些圖像小心拼接起來。
  • 不用通過全景相機APP,就能自己上傳微博全景圖
    微博全景圖現在大家也很熟悉了,很多人也在問是怎麼上傳到微博的,之前基本都是通過全景相機拍攝全景圖分享到微博,但是很多通過單反和gopro等拍攝的自己的全景圖怎麼上傳呢
  • PTGui Pro製作全景圖簡易教程(附全景素材下載)
    PTGui Pro是一個多功能的圖片全景製作工具,提供可視化界面來實現對圖像的拼接,從而創造出高質量的全景圖象。
  • 如何使用微軟ICE,拼接並導出你的全景圖 | VeeR有料
    圖片拼接是一個拼接很多場景重合的圖片,使它們形成一張全景圖或高解析度圖像的過程。一般來說,圖片拼接的過程都需要在電腦軟體上進行,並且這個過程需要圖像近乎一致的重疊,並且曝光度也要一致,才能形成無縫拼接,雖然一些拼接算法會得益於圖片有不同曝光度的情況。一些多鏡頭的系統可以將圖片在內部直接拼接好,還有些可以用手機完成拼接。
  • 製作360度全景圖
    360全景,即通過對專業相機捕捉整個場景的圖像信息或者使用建模軟體渲染過後的圖片,使用軟體進行圖片拼合,並用專門的播放器進行播放,即將平面照片或者計算機建模圖片變為360 度全觀,用於虛擬實境瀏覽,把二維的平面圖模擬成真實的三維空間,呈現給觀賞者。 全景圖優點相比較一般的效果圖和三維動畫,全景圖具有如下優點:1.
  • 【重磅更新】印刷電路板產業鏈全景圖
    #如何獲取以上高清完整版資料#方式一掃碼購買【2019年最新版】100大產業鏈全景圖*不止可獲取以上高清完整版資料,還可獲取另外99份產業鏈全景圖方式二成為新材料在線®APP會員點擊下方關鍵字,閱讀往期文章熱門通訊錄:醫療器械 | 鋰電池 | 高性能纖維 | 軌道交通 | 汽車管路 | 紡織新材料 | 家居建材 | 家電 | 包裝 | 手機外殼 | 智能硬體 | 3D列印 | 新材料新資本 | 新能源汽車&動力電池 | 磁性材料 | 高性能發泡 | 全球主機廠零部件 |全球電子功能材料
  • 精緻全景圖 | 系統調用是如何實現的
    在講具體的細節之前,我們先根據上圖,從整體上看一下系統調用的實現。系統調用的實現基礎,其實就是兩條彙編指令,分別是syscall和sysret。syscall使執行邏輯從用戶態切換到內核態,在進入到內核態之後,cpu會從 MSR_LSTAR 寄存器中,獲取處理系統調用內核代碼的起始地址,即上面的 entry_SYSCALL_64。
  • 連比爾蓋茨也在用的米家全景相機到底有什麼魔力?
    最近全景照片已經開始大火特火起來了。連比爾蓋茨都用米家全景照相機拍了全景照片發微博,如果你自詡科技達人,這都不知道的話,那你真的OUT了。
  • cuckoo沙箱技術分析全景圖
    但網絡上關於cuckoo的介紹實在有限,於是花了點時間將cuckoo代碼進行了粗淺分析,整理繪製了cuckoo技術全景圖,分享出來,歡迎探討。在看全景圖前,先看看cuckoo官網的一張技術架構圖:我們從cuckoo的啟動和一次分析任務的發起,來看看Cuckoo的整體流程是如何運轉的。首先是host部分,Cuckoo Host是採用Python開發,最初的啟動流程如圖: