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