上一篇簡單介紹了cornerstone.js的相關使用介紹和基於cornerstone的web庫cornerstoneWADOImageLoader,在實際開發中遇到了相關的一些問題,在這里說明一下,也是防止以后再次遇到相似的問題,以便查看。
對於一些外部庫,我們不了解實現的每一個細節,所以說就有可能遇到各種各樣的坑,通過使用cornerstoneWADOImageLoader庫文件,我從中通過爬"坑"體會到了一個道理:盡量不要依賴庫自帶變量。見代碼:
/* 假設需要獲取cornerstoneWADOImageLoader中imagepath的值 在自己的程序中可能多次需要調用這個path值 */ /*第一種可能bug的寫法*/ var path1=cornerstoneWADOImageLoader.imagepath; ... var path2=cornerstoneWADOImageLoader.imagepath; ... 這種寫法出現bug的次數比較多,不一定每次都有bug,因為可能跟調用的變量上下文環境有關,a變量調用沒有什么限制條件,b變量也許會有一些上下文限制條件(當然這種情況很少, 但是遇到過bug),或一些其他的限制條件。 /*避免bug的寫法很簡單*/ var path=cornerstoneWADOImageLoader.imagepath;//定義全局 .. var path1=path; .. var path2=path; .. 自定義變量接收cornerstoneWADOImageLoader的變量,這樣不僅可以避免bug,也可以優化一些性能。我在項目中多次遇到這個bug,第一種寫法的時候,明明上邊某一行代碼調用變量成功了,在下文 在使用這個變量的時候偶爾就會出現無法獲取變量的提示。
- 坐標轉換
實際需求,不僅僅是顯示Dicom圖像,還需要在畫布上做一些操作
縮放平移選取:
上圖左邊是原始圖片,中間是縮放平以后的圖片,右是縮放平移后選取的圖片(這是一張肺部ct圖,圖中紅色的圈是對結節的手動標注)
坐標轉換的問題來了:第三張圖中,紅色圓圈的實現方式很簡單,就是在canvas上繪制紅色的點,然后連起來,簡單的一個畫筆功能。那么問題是,當圖像縮放平移后,如何得知畫筆相對於圖像的坐標?
設么意思呢?:請理解第三張圖,假設圖中紅色的點坐標是(160,320),---圖中紅圈是由n個點組成的,我們假設他一個點的坐標,只要求出一個點的坐標轉換方法,其他的也一樣。那么無論圖片怎么動,這個點的坐標都是(160,320),他是相當Canvas的坐標,(點是繪制在canvas上,圖片也是繪制在canvas上,無論圖片怎么移動,點是不會動的。)那么當用戶在放大平移這張圖片以后,找到了一個病變的地方,圈出來,那么現在想要獲取這個紅圈在原圖上的位置,就要進行坐標轉換。如果不理解換一種思路,在你的電腦上查看一張圖片或者照片,現在拖動照片窗口的位置,然后放大照片或縮小照片,現在拿左手手指點住顯示屏,點中你要關注的點,不要拿開,右手使用鼠標把敞口和圖片還原到原來的位置大小,那么你現在的手指還在你點中的位置上么?這就是坐標轉換,我們的需求是醫生在查看Dicom圖像,手動標注圖像的可疑位置,然后我們還原紅圈通過算法檢測醫生標注的是否正確,這就是坐標轉換的初衷
直接給出公式:(pos.x-(imgX+(cv1.width/2-img.width*scale/2)))/scale;
@2017.12.21備注
當初寫這章博客的時候,畫布的尺寸設計了原始尺寸512*512,所以在坐標轉換的問題上沒有那么多可能出現的問題,新版本改進后,畫布的尺寸是自適應屏幕的,然后今天在寫的過程中直接套用了公式,把img.width也設置了畫布的尺寸,最后有進行了一個(scale_n=512/cv.width)的縮放調整,結果各種bug。寫在這里強調一下,也是為了以后看的時候長有個參考:cv1.width不用說就是當前畫布的尺寸,img.width是原始圖片的寬度。按照公式套不用再做任何轉換直接是正確結果。
pos.x是點的x坐標,imgX是鼠標x方向移動量,cv1是畫布,img是圖片,scale縮放比例,公式給出了x的轉換,對於y的轉換直接改成對應y值即可,然后width要改成height,這樣就可以通過鼠標點擊的點,轉換到原圖上對應的點,說了這么多,不是主題。。。。。只是正好介紹一下坐標轉換,公式可以用於其他任何相關操作的開發項目。
要說的主題是:cornerstone的viewpoint的viewport.translation屬性,我們在自定義畫布上,可以獲取到鼠標移動量,在使用cornerstoneWADOImageLoader這個庫,它只需要你提供一個div,它自動會在這個div上創建canvas(目前都是512的)然后繪制,所以說你根本無法獲取到canvas的屬性,但是他提供了api,可以直接使用,但是有坑。
看代碼:
else if(3 == e.which) { //判斷是否為右鍵 console.log(3); lastX = e.clientX; lastY = e.clientY; $(document).mousemove(function (e) { deltaX = e.clientX - lastX, deltaY = e.clientY - lastY; lastX = e.clientX; lastY = e.clientY; viewport = cornerstone.getViewport(element); viewport.translation.x += (deltaX / viewport.scale); viewport.translation.y += (deltaY / viewport.scale); // viewport.translation.x += deltaX ; viewportX=viewport.translation.x; // viewport.translation.y += deltaY ; viewportY=viewport.translation.y; console.log(viewportX); console.log(viewportY); cornerstone.setViewport(element, viewport); });
當鼠標右鍵點擊時,默認對圖片操作平移功能。
注意這個變量 viewport.translation.x,這就是他提供的默認的圖像移動屬性,通過+=鼠標移動量,從而對讓圖像平移,注意代碼注釋的部分,最開始我的實現方式是:
// viewport.translation.x += deltaX,這才是真正正確的操作方法
平時在canvas移動圖像的步驟是:1.獲取鼠標移動量 2.計算圖片的起始位置+鼠標移動 3.清空畫布,然后根據2算出的位置重新繪制drawimage(),現在這個庫給出了translation的屬性,無需上述復雜操作(也操作不了,無法獲取畫布),直接賦值。但是按照常規的算法// viewport.translation.x += deltaX,圖片完全可以移動,沒有問題,鼠標和圖片的相對位置可就不一樣了:
截圖的時候截不到鼠標圖標,我就根據位置自己畫了一個,紅色的箭頭(兩次我都是點在圖片上,然后進行平移)
左圖是使用viewport.translation.x += (deltaX / viewport.scale),可以看到鼠標的位置還是在圖片上,相對位置並沒有改變。
右圖是使用viewport.translation.x += deltaX,鼠標我開始也是點在圖片上向右拖動的,但是圖片向右移動量大於鼠標移動量,造成了圖中的現象,圖片走的多了。此時,圖片的移動量,根本就不是鼠標的移動量,坐標轉換種的imgX鼠標移動量對應的不是圖片移動的距離,先跨一步,然后回來說這個移動量的問題--@1。
通過使用 viewport.translation.x += (deltaX / viewport.scale),那么對應的坐標轉換公式:
(pos.x-(viewportX*viewport_Scale+(cv1.width/2-img.width*viewport_Scale/2)))/viewport_Scale
公式中viewportX=viewport.translation.x,我自定義了變量賦值,就是上文提到的,我在這里直接使用viewport.translation.x,就報錯了,無法獲取,然后我用其他變量接受了一下。這不是重點
viewportX*viewport_Scale這個才是重點
上文中,/scale,下面公式又*scale,不是沒有改變嗎?
因為,原公式是沒有*scale的 ,轉換公式這里只是imgX
解釋:公式的大體思路是:鼠標拖動圖片向右移動了50px,那么我在此時標注紅圈,那么如果要獲取紅圈相對於原圖的位置,我的紅圈要向左-50px,才對,對的就是這個思路,但是,這里鼠標的移動量等於圖片的移動量,這也就是@1的問題所在,對於它的api,沒有/scale的話,鼠標移動的距離根本不是圖片移動的距離,小於圖片移動的距離(多少取決於scale),也就是鼠標向右移動了50px,實際圖片移動了60px,那么你在用紅圈的點-50px,得到的並不是實際相對於圖片的位置
以上種種也就是/scale的原因,至於為什么/scale,而不是/scale*2,而不是/scale*3?這要看它的translation的api是怎么定義的,我是在他官方的例子中找到的答案,所以在這里/scale,在下文在乘以scale,確保公式的定義的鼠標移動量。
先保證圖片和鼠標同步移動,然后再使用公式。
說了好多,寫的1個多小時,我發現寫隨筆,可以一邊寫一邊梳理當時的思路。
還有一點:使用時需要配置這兩個腳本路徑,如下。谷歌翻譯,大概懂意思就行
Web工作者框架需要一些配置,因為Web工作者需要源文件的路徑。由於基石並不執行源文件位置的約定,您必須告訴基礎Web工作者框架,其中web worker文件是可以正確加載的。這是通過cornerstoneWADOImageLoader.webWorkerManager.initialize()函數完成的。您必須先調用此函數,然后才能啟動Web工作任務(或使用基石加載映像),以使Web工作者代碼正確加載。
最小配置
以下是最小配置對象的示例。
var config = { webWorkerPath : ' ../../ dist / cornerstoneWADOImageLoaderWebWorker.js ', taskConfiguration : { ' decodeTask ' : { codecsPath : ' ../ dist / cornerstoneWADOImageLoaderCodecs.js ' } } }; cornerstoneWADOImageLoader。webWorkerManager。initialize(config);
在上面的示例中,您將看到兩個路徑,一個到cornerstoneWADOImageLoaderWebWorker.js,一個到cornerstoneWADOImageLoaderCodecs.js文件。這兩個文件都可以在該存儲庫的dist文件夾中找到。您必須在您的Web服務器上托管這兩個文件,並提供一個路徑。