孫新佳,田宏哲,羅凱
(北京華能新銳控制技術(shù)有限公司,北京 102209)
隨著現(xiàn)代技術(shù)的發(fā)展,人們對交互式應(yīng)用的要求也提升到一個新的層次。傳統(tǒng)的工業(yè)組態(tài)應(yīng)用軟件大多提供二維的圖形畫面,通過添加位置移動、顏色變化等動畫來傳達設(shè)備的運行信息。但是這種圖形只是單方面給用戶呈現(xiàn)了系統(tǒng)設(shè)備的側(cè)視圖或者俯視圖,并沒有給用戶反映整體的效果。隨著技術(shù)的不斷更新,有些軟件可以展現(xiàn)三維模型,但是需要在客戶端上安裝插件才能實現(xiàn),其中包括UNITY3D、TURNTOOL和QUEST3D等[1]。這樣就帶來了很大的局限性,其中就涉及到插件與系統(tǒng)環(huán)境、瀏覽器等的兼容性問題,影響系統(tǒng)的穩(wěn)定性。
隨著智能手機的大力發(fā)展,極大地推動了移動端和電腦端Web開發(fā)的興起,越來越多的應(yīng)用軟件采用B/S架構(gòu),這樣移動端和電腦端無需額外安裝客戶端軟件,只要通過系統(tǒng)自帶的瀏覽器就能夠直接訪問部署在服務(wù)器上的應(yīng)用。Web3D技術(shù)也越來越多地引起大家的關(guān)注,其中WebGL(web graphics library)是一種3D繪圖協(xié)議[2],這種繪圖技術(shù)標(biāo)準(zhǔn)允許把JavaScript與OpenGL結(jié)合起來[3-4]。WebGL可以為HTML5 Canvas提供硬件3D加速渲染。WebGL標(biāo)準(zhǔn)是免費開放的,相對于私有的Adobe Flash Player、微軟Silverlight,WebGL具有極大的優(yōu)勢:通過HTML腳本本身實現(xiàn)Web交互式三維動畫的制作,無需任何瀏覽器插件的支持;利用底層的圖形硬件加速功能進行圖形渲染,實現(xiàn)統(tǒng)一的、標(biāo)準(zhǔn)的、跨平臺的OpenGL接口[5]。目前已有很多不錯的WebGL開源框架,例如GLCE、SceneJS、CubicVR、THREE.js等[6],其中THREE.js最受歡迎,它用簡單直觀的語法封裝了WebGL常用的三維對象,代碼中使用了很多調(diào)用圖形引擎的高級技巧,極大地提高了性能[7-8]。由于其完全采用JavaScript語言,所以很容易與其他瀏覽器組件進行交互,帶來很好的體驗效果?,F(xiàn)在很多行業(yè)應(yīng)用了WebGL技術(shù),如網(wǎng)頁3D動畫[9]、交互式三維地球模型[10]、人臉模型建立[11]等。python是一種簡單的、解釋型的、交互式的、可移植的、面向?qū)ο蟮某呒壵Z言,具有非常清晰的語法特點并適用于多種操作系統(tǒng),在國際上非常流行,得到越來越多的應(yīng)用。在圖像處理方面,python擴展了很多高級的編程工具包,為圖像數(shù)據(jù)處理提供了強大的數(shù)值計算支持。
本文主要解決的問題是將俯視的煤場灰度圖做空間拉伸,渲染成3D圖形。主要以THREE.js框架為基礎(chǔ),構(gòu)建一套煤場3D可視化系統(tǒng),實現(xiàn)移動端或電腦端發(fā)送請求到三維圖像渲染顯示。具體實現(xiàn)前端請求發(fā)送,后端通過python程序處理二維圖像并將圖像信息存儲于JSON文件,前端利用ajax[12]讀取圖像JSON數(shù)據(jù)構(gòu)建點云數(shù)據(jù)后通過THREE.js進行3D渲染呈現(xiàn)煤場三維模型。
由于JavaScript不能直接對圖像進行處理操作,而python是在圖像處理方面有很強的實用性腳本語言,同時python語言有可移植性可以在絕大多數(shù)的平臺上直接運行[13]。
本文的原始數(shù)據(jù)是一個安裝在斗輪機上激光掃描儀生成的包含煤場空間信息的二維圖片,圖像中的明亮程度表示煤場的高度分布情況。在圖像數(shù)據(jù)處理中,一般情況下采用矩陣來表示圖像的數(shù)據(jù)信息,矩陣中的每一個元素代表圖像對應(yīng)像素點的RGB值。由于JavaScript不能直接對圖像進行像素級的處理操作,所以在這里通過python腳本程序?qū)⑺L問的圖像進行一定程度上的處理,并將圖像的信息寫入到JSON文件中。JSON是存儲和交換文本信息的語法,類似于XML,但是比XML更小、更快、更容易解析,尤其對于圖像這種幾十萬個數(shù)據(jù)而言,這種輕量級的文本傳輸格式不失為一種最佳的選擇。
讀取原始圖像數(shù)據(jù)后轉(zhuǎn)化為灰度圖,灰度圖中的數(shù)據(jù)代表這一點的明亮程度,在本文中的物理意義是煤場在這一點上的高度信息。圖中包含很多的噪聲,在三維重建中這種噪聲會被放大,影響模型呈現(xiàn)效果,所以圖像數(shù)據(jù)讀取后在程序中再進行中值濾波處理。中值濾波是一種非線性平滑技術(shù),將每一個像素點的灰度值設(shè)置為該點鄰域窗口內(nèi)的所有像素點灰度值的中值,這樣在很大程度上消除圖像中的沖擊噪聲[14]。
g(x,y)=med(f(x-k,y-l),(k,l∈W))
(1)
式中:f(x,y),g(x,y)分別為原始圖像和處理后的圖像的像素點;W為二維模板,通常采用3×3或5×5區(qū)域,也可以是不同形狀。
如圖1所示,圖1(a)為原始圖像(原始數(shù)據(jù)),圖1(b)為做濾波處理后的圖像數(shù)據(jù),通過對比可以發(fā)現(xiàn)做了平滑濾波之后,原始數(shù)據(jù)中不合理的噪聲數(shù)據(jù)被清除,處理后的圖像更加接近于現(xiàn)實情形。
圖1 原始圖像和平滑處理后的圖像
對于以上圖像,本文采用Tenengrad梯度函數(shù)對處理前后的圖像進行光滑度分析。Tenengrad梯度函數(shù)采用Sobel算子分別提取水平和垂直方向的梯度值,基于Tenengrad梯度函數(shù)的圖像光滑度定義如下:
D(f)=∑y∑x|G(x,y)|
(2)
G(x,y)形式如下:
(3)
Gx和Gy分別是像素點(x,y)處Sobel水平和垂直方向邊緣檢測算子的卷積,本文采用的Sobel算子模板如下:
x水平方向Sobel算子:
y垂直方向Sobel算子:
故原圖x、y方向的卷積分別為:
Gx=Sx*A,Gy=Sy*A
(4)
式中:A表示原始灰度圖像。通過基于Tenengrad梯度函數(shù)的圖像光滑度公式可得圖2和表1。
圖2 濾波后圖像的Tenengrad梯度圖
圖3 原圖的Tenengrad梯度圖
表1 光滑度對比表
通過圖2、圖3中圖像梯度圖的幅值,以及表1中的數(shù)值,可知經(jīng)過濾波處理后的圖片去除了大部分的噪聲干擾,圖像更加光滑,更符合現(xiàn)場情況。
經(jīng)過濾波降噪處理后,通過python腳本按照表2格式將圖像信息寫入到JSON文件中。
表2 data.json文件數(shù)據(jù)結(jié)構(gòu)表
表1中,height表示圖像尺寸的長度,width表示圖像尺寸的寬度;data存儲圖像矩陣的數(shù)據(jù),從矩陣的第一行開始依次存儲整個矩陣的數(shù)據(jù),矩陣數(shù)據(jù)的坐標(biāo)信息可以通過矩陣的height和width去計算,而不再單獨存儲數(shù)據(jù)在矩陣的坐標(biāo)信息,選擇這樣的存儲方式可以減少很大的數(shù)據(jù)傳輸量,使系統(tǒng)響應(yīng)更快。
眾所周知,點動成線,線動成面,面動成體,一個面片都可以通過3個點確定的三角形或者4個點確定的四邊形來構(gòu)建,而由有限個這樣的面片可以近似逼近任何一個面。在三維建模領(lǐng)域,建模的時候使用四邊形是大家經(jīng)常采用的方式,因為四邊形比三角形更容易增強和平滑。但是對于渲染和游戲引擎來講,使用三角形更加容易,因為任何一個形狀都可以渲染成多個三角形。THREE.js提供函數(shù)THREE.Vector3()來確定空間坐標(biāo)中的一點,將三維模型所有的點全部聲明并實例化存儲于數(shù)組vertices,函數(shù)THREE.Face3()用來使用vertices中的三個點來構(gòu)建一個三角形,將vertices中所有的點按照所構(gòu)建的模型需要進行組合,這樣就完成了空間模型所有三角形的構(gòu)建工作[15]。
二維數(shù)字圖像可以通過二維數(shù)據(jù)矩陣來表示,如果圖像為彩色圖像,任何顏色都有紅、綠、藍3種顏色組成,那么矩陣的每個元素的顏色值為RGB(R,G,B)。所謂灰度圖像,即每個矩陣元素為RGB(R,G,B),且R=G=B=Gray,其值的大小表示圖像的亮度信息。由RGB色轉(zhuǎn)灰度色有3種算法:①浮點算法:Gray=R*0.3+G*0.59+B*0.11。②整數(shù)算法:Gray=(R*299+G*587+B*114+500)/1 000。③平均法:Gray=(R+G+B)/3。為避免低速的浮點運算,在大多數(shù)的情況下采用整數(shù)算法,所以本文通過后端程序通過python腳本將彩色圖像轉(zhuǎn)化為灰度圖,其圖像數(shù)據(jù)矩陣如圖4所示。
圖4 圖像數(shù)據(jù)矩陣示意圖
圖4表示一個圖像數(shù)據(jù)矩陣,a、b、c、d點數(shù)據(jù)分別包含對應(yīng)圖像像素點在數(shù)據(jù)矩陣的坐標(biāo)及亮度值,這3個數(shù)據(jù)即為對應(yīng)像素點在空間的坐標(biāo),每個像素點在矩陣的位置坐標(biāo)即為三維空間XOZ平面上的坐標(biāo),像素點的亮度值即為三維空間Y軸的坐標(biāo),這樣通過獲取圖像數(shù)據(jù)矩陣可以確定圖像中每一個像素點在控制XYZ軸的坐標(biāo)。(a,b,c)、(a,d,c)或(a,b,d)、(b,d,c)分別表示2個三角形,這樣遍歷整個圖像數(shù)據(jù)矩陣,那么整個圖像就可以通過這樣的三角形組合顯示。算法步驟如下:
①獲取圖像高度和寬度,即height,width。
②構(gòu)建空間數(shù)據(jù)點集vertices。
//遍歷整個數(shù)據(jù)矩陣
for (i=0;i for(j=0;j { x=i; z=j; y=arr[i,j]; //構(gòu)建空間數(shù)據(jù)點集 vertices.push(Vector3(x,y,z)) } ③構(gòu)建空間三角面集faces。 //遍歷整個數(shù)據(jù)矩陣 for(i=0;i for(j=0;j a=i*width+j; b=i*width+j+1; c=(i+1)*width+j+1; d=(i+1)*width+j; faces.push(Face3(a,b,c)); faces.push(Face3(a,d,c)); } } 首先通過python腳本讀取原始二維圖像,并做灰度化處理,再對灰度圖像做中值濾波處理,清除圖像中的沖擊噪聲,處理之后將灰度圖的寬度、高度及亮度值信息按照表2格式寫入到data.json文件中。 對于JSON文件,JavaScript可以對其直接進行解讀,將JSON保存的圖像數(shù)據(jù)信息全部讀取到變量中存儲,代碼如下: var arr=new Array(); var width; var height; $.ajaxSettings.async=false; $.get(′data.json′,function(data){ height=data[″size″][0]; width=data[″size″][1]; for(var i=0;i<= height;i++){ arr[i]=new Array(i); for(var j=0;j<= width;j++){ arr[i][j]=data[″data″][j+i*(width+1)]]; } } },′json′); 這里,二維數(shù)組arr存儲的即為圖像矩陣的數(shù)據(jù)。所要注意的是ajax的請求為同步,即$.ajaxSettings.async=false,否則會影響模型的加載。 讀取數(shù)據(jù)后,接下是構(gòu)建空間散點和三角形,算法如下: function (func,slices,stacks) { THREE.Geometry.call(this); this.type = ′ParametricGeometry′; this.parameters = { func:func, slices:slices, stacks:stacks }; var verts = this.vertices; var faces = this.faces; var i,j,p; var u,v; var stackCount = stacks + 1; var sliceCount = slices + 1; for (i = 0;i <= stacks;i ++) { v = i; for (j = 0;j <= slices;j ++) { u = j; p = func(u,v); verts.push(p); } } var a,b,c,d; for (i = 0;i < stacks;i ++) { for (j = 0;j < slices;j ++) { a = i * sliceCount + j; b = i * sliceCount + j + 1; c = (i + 1) * sliceCount + j + 1; d = (i + 1) * sliceCount + j; faces.push(new THREE.Face3(a,b,d)); faces.push(new THREE.Face3(b,c,d)); } } this.computeFaceNormals(); this.computeVertexNormals(); }; function(u,v){ //構(gòu)建空間點函數(shù) x=u; z=v; y=arr[x][z]; return new THREE.Vector3(x,y,z); } 通過上述算法,利用THREE.js框架渲染后的煤場如圖5所示。 圖5 煤場空間三維圖像 圖6是利用iconics Genesis64軟件渲染的三維效果,將位圖格式(.bmp)的圖像導(dǎo)入到軟件中,再設(shè)定其部分參數(shù),軟件獲取圖像像素點值大小自動做拉伸處理,最終渲染成三維效果。對比2幅圖像,可以看出,iconics軟件只是對圖像做了空間的拉伸,并不具備消除圖像中沖擊噪聲的功能,同時只支持電腦端訪問;本文設(shè)計的系統(tǒng)通過后端python程序?qū)D像做平滑處理后,能夠?qū)⒋蟛糠謭D像噪聲濾除掉,這樣渲染出來的三維效果更加平滑,貼近現(xiàn)實,效果更好,同時支持移動端和電腦端無插件瀏覽。 圖6 GENESIS64渲染煤場三維圖像 本文設(shè)計了一套基于B/S架構(gòu)利用二維圖像重建三維場景的系統(tǒng),主要應(yīng)用于煤場三維重建領(lǐng)域。用戶通過移動端和電腦端發(fā)送請求,系統(tǒng)后臺程序自動處理所請求的煤場圖像信息并轉(zhuǎn)化為JSON數(shù)據(jù)推送到前端,前端不借助任何第三方插件自動渲染出煤場的三維模型。通過與其他軟件對比,本文所設(shè)計的三維重建系統(tǒng)在項目中具有更好的渲染效果,能夠清除圖像中絕大部分的沖擊噪聲,并且具有很強的擴展性,可以與其他系統(tǒng)嵌套使用,對于煤場信息管理具有較強的便利性和實用性。3 三維重建
4 結(jié)束語