基於HTML5的PACS--HTML5影像處理

來源:互聯網
上載者:User

在此之前,此系統是結合DICOM的WADO標準,在瀏覽器裡通過javascript操作返回的JPG圖片。這種伺服器端解析,用戶端展現的方式,對實現映像的移動、縮放、旋轉、測量等映像操作能夠實現即時的互動。但這種方式存在著幾個弊端:

1.擷取映像上的CT值(鈣化值)資訊的時候,要頻繁的和伺服器進行互動。

2.調整映像的窗寬窗位或者對映像進行反色,也要和伺服器進行頻繁的互動。

3.對映像進行測量(長方形測量,橢圓測量等)只能擷取到面值和周長的簡單的資訊,這對於醫生的診斷沒多大的用處,實際運用中需要知道所測量的地區的最大值、最小值、方差值、均值等測量資訊。

 以上的缺點歸結為一點:即本地沒有處理像素資訊的操作。但是HTML5對於像素級處理的能力已經支援得很好,完成可以實現用戶端對像素資訊的操作。所以為瞭解決以上問題最近對系統做了一次比較大的升級。即用戶端端直接操作DICOM的像素資料進行JS端映像的產生以及JS端實現窗寬窗位的調整。

擷取dicom中的像素資料,可考慮以下兩種方式:

A:伺服器端直接以位元組流的方式返回DICOM檔案,用戶端用JS來接收位元組流,並負責解析DICOM中的映像資料,這種方式不僅要根據DICOM 的傳輸文法(0002,0010)Transfer Syntax UID,還要根據  (0028,0002)Samples per pixel、(0028,0004)Photometric Interpretation,(0028,0010)Rows,(0028,0011)Columns,(0028,0100)Bits Allocated,(0028,0103)Pixel Representation等標籤來確定像素資料的結構,複雜點的可能還會用到尋找表來尋找((0028,0004)Photometric Interpretation的值等於==PALETTE COLOR)。對於非壓縮的顯示VR或者是隱形VR, (0028,0004)Photometric Interpretation等於MONOCHROME1或者MONOCHROME2來說JS解析出像素資料確實很方便,但是DICOM檔案各式各樣,要 寫出包羅給種傳輸文法以及各種像素結構的JS檔案確實很費勁。還要考慮到多幀生動影像,如果多針映像很大整個檔案下載下來解析估計瀏覽器會徹底奔潰。所以 覺得這種方式不太可行。(雖然這過程中實現了顯示VR的DICOM檔案的JS解析,但是中途考慮到複雜性和難度還是放棄了)。

B:從伺服器端擷取DICOM檔案的像素數組,既然目前基於C/S模式的PACS已經相當成熟,各式各樣的第三方開源的dicom解析工具如 DCMTK,DCM4CHE,MDCM,OPENDICOM等也相當的多,用開源的DICOM解析工具擷取到像素資料也相當的方便。所以在伺服器擷取到像 素資料返回給JS端,讓JS端直接操作像素資料來產生要顯示的映像。對於多幀映像也可以按需按幀的從伺服器下載像素資料。

言歸正傳,目前此系統是基於第二種方式來實現。需要特別注意的是:做窗寬窗位調整的時候要先做Hounsfield 值的轉換。 

HU[i] = pixel_val[i]*rescaleSlope+ rescaleIntercept。窗寬窗位的調整使用了線性window-leveling 演算法針對CT/MR等映像,或者是非線性gamma演算法針對DX映像(即當windowWidth比較大的時候要考慮非線性gamma演算法,因為線性 演算法中每windowWidth/255個原始密度會壓縮成一個顯示灰階,windowWidth很大的時候損失可能會很大)

//線性window-leveling演算法min = (2*windowCenter - windowWidth)/2.0 - 0.5;  max = (2*windowCenter + windowWidth)/2.0 - 0.5;for (var i = 0; i != nNumPixels; i++){    showPixelValue = (pixelHuValue[i] - min)*255.0/(double)(max - min);} //非線性gamma演算法min = (2*windowCenter - windowWidth)/2.0 - 0.5;  max = (2*windowCenter + windowWidth)/2.0 - 0.5;for (var i = 0; i != nNumPixels; i++){    showPixelValue = 255.0 * Math.pow(pixelHuValue/(max-min), 1.0/gamma);}

如下代碼展示JS端如何用後台擷取到的像素資料產生映像。其中用到了尋找表的概念。

/** * @author http://www.cnblogs.com/poxiao * pixelBuffer代表是從後台擷取到的像素資訊數組,代碼只列出了單色灰階映像的情況, * 如果是三色的RGB映像自己稍微改動下代碼即可。篇幅有限不在敘述。 **/var pixelBuffer;//width 代表映像的寬度,即DICOM中的標籤(0028,0011)Columnsvar width;//height 代表映像的高度,即DICOM中的標籤(0028,0010)Rowsvar height;/** * @windowCenter 代表當前要顯示的窗位 * @windowWidth 代表當前要顯示的窗寬 * @bitsStored (0028,0101) 根據每個像素的儲存位元產生尋找表大小 * @rescaleSlope (0028,1053)用於計算HU值 * @rescaleIntercept  (0028,1052)用於計算HU值 * **/function createImageCanvas(windowCenter,windowWidth,bitsStored,rescaleSlope,rescaleIntercept){    var lookupObject=new LookupTable();    lookupObject.setData(windowCenter,windowWidth,bitsStored,rescaleSlope,rescaleIntercept);    lookupObject.calculateHULookup();    lookupObject.calculateLookup();        var imageCanvas=document.createElement("canvas");    imageCanvas.width = width;    imageCanvas.height =height;    imageCanvas.style.width = width;    imageCanvas.style.height = height;    var tmpCxt = imageCanvas.getContext("2d");    var imageData = tmpCxt.getImageData(0,0,width,height);    var n=0;    for(var yPix=0; yPix<height; yPix++)    {        for(var xPix=0; xPix<width;xPix++)        {            var offset = (yPix * width + xPix) * 4;            var pixelValue=lookupObject.lookup[pixelBuffer[n]];            imageData.data[offset]=    pixelValue;            imageData.data[offset+1]=pixelValue;            imageData.data[offset+2]=pixelValue;            imageData.data[offset+3]=255;            n++;        }    }    tmpCxt.putImageData(imageData, 0,0);        return imageCanvas;};/** * 像素尋找表,主要要先根據rescaleSlope和rescaleIntercept進行Hounsfield值的轉換 * HU[i] = pixel_val[i]*rescaleSlope+ rescaleIntercept */function LookupTable(){    this.bitsStored;    this.rescaleSlope;    this.rescaleIntercept;    this.windowCenter;    this.windowWidth;        this.huLookup;    this.lookup;}LookupTable.prototype.setData=function(wc,ww,bs,rs,ri){        this.windowCenter=wc;    this.windowWidth=ww;    this.bitsStored=bs;    this.rescaleSlope=rs;    this.rescaleIntercept=ri;};LookupTable.prototype.setWindowingdata=function(wc,ww){    this.windowCenter=wc;    this.windowWidth=ww;};LookupTable.prototype.calculateHULookup=function(){    var size=1<<this.bitsStored;    this.huLookup = new Array(size);    for(var inputValue=0;inputValue<size;inputValue++)    {        if(this.rescaleSlope == undefined && this.rescaleIntercept == undefined) {            this.huLookup[inputValue] = inputValue;        } else {                   this.huLookup[inputValue] = inputValue * this.rescaleSlope + this.rescaleIntercept;        }    }};/** * 窗寬窗位的調整線性Window-leveling演算法 * 非線性gamma演算法,稍微修改下: *  var y=255.0 * Math.pow(this.huLookup[inputValue]/this.windowWidth, 1.0/gamma); * **/LookupTable.prototype.calculateLookup=function(){        var size=1<<this.bitsStored;    var min=this.windowCenter-0.5-(this.windowWidth-1)/2;    var max=this.windowCenter-0.5+(this.windowWidth-1)/2;    this.lookup=new Array(size);    for(var inputValue=0;inputValue<size;inputValue++)    {        if(this.huLookup[inputValue]<=min){            this.lookup[inputValue]=0 ;        }else if (this.huLookup[inputValue]>max){            this.lookup[inputValue]=255;        }else{                            var y=((this.huLookup[inputValue]-(this.windowCenter-0.5))/(this.windowWidth-1)+0.5)*255;            this.lookup[inputValue]= parseInt(y);        }    }};

滑鼠調整窗寬窗位的時候JS端產生映像+繪製圖形的速度。

1.512 X 512大小的CT映像調整窗寬窗位速度

 2.512 X 512大小的彩色CT映像調整窗寬窗位速度

 3.512 x 512大小的MR映像調整窗寬窗位速度

 4.2057 X 1347大小的CR映像調整窗寬窗位速度

5.有了像素資訊後就可以在用戶端即時的擷取到CT值了。

6:有了像素資訊後測量也可以擷取到測量地區的最大值、最小值、方差值、均值等測量資訊了

進測試,調整窗寬窗位時HTML5上繪製圖形的時間還是很快的,總的繪製時間在10毫秒的數量級,而且發現繪製時間還可以變少,這繪製時間包括了圖 像邊角上的文字資訊,但是HTML5繪製文字的資訊效率明顯比繪製映像的效率要底,所以不必每次重新整理都繪製文本資訊,可以加以參數控制在映像切換或者調窗 寬窗位的時候也就是文本資訊變化的時候才繪製文字資訊。關於映像的產生時間,發現映像的產生時間和映像的寬X高成正比,映像越大所需時間越長,對於 CT/MR等映像時間大概在幾十個毫秒級。對於2057X1347的CR映像時間大概在400毫秒級,對於2000X3000多的DX映像產生映像的時間 就有點卡頓了,要1秒-2秒左右。。。這速度還得想辦法最佳化有木有。。。。。還有對於DX映像調整窗寬窗位雖然使用了gamma演算法,但是出來的映像,我 總感覺得沒有用第三方工具比如RadiAnt上看見的光滑,雜訊有點大。所以在沒得到更好的解決方案前,目前DX的映像只能特殊化即保留原來的方式在服務 器端直接產生JPG讓用戶端直接繪製,希望會DICOM映像演算法的大神們看到此文章後能給小弟我一點關於DX調窗寬窗位的意見,是不是還要用到別的演算法啥的?。先謝謝了



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。