NoduleTracker.ahk 開發日誌 (2026/4~6)

距離上一篇 update 又過了三個月。在臨床診斷肺結節(Lung Nodule)的繁重日常中,這個小工具已經成為我讀 CT 影像時的靈魂伴侶。

這季的調整幅度相當大。不僅在 4 月初對程式碼進行了「骨架大改造」,也陸續解決了許多在實際讀片時遇到的奇葩痛點。以下整理了這三個月來的開發脈絡與心路歷程。


1. 程式碼的骨架大改造:邁向 Class-based 類別化架構

在 4 月以前,NoduleTracker.ahk 是採用傳統的程序式(Procedural)寫法。當時為了貪圖開發快速,全域變數與輔助函數散落各處。隨著功能越來越多(像是動態排序、影像跳轉等),程式碼行數漸漸逼近兩千行,每次要修改邏輯都像在踩地雷,維護起來極為吃力。

於是在 4 月 2 日,我花了一整天把整個專案翻新,將所有邏輯重構成 class NoduleTracker 的類別化架構。

原本零散的全域變數全部收攏為類別的實例屬性(例如 this.NoduleData),而 UI 的初始化、事件綁定與熱鍵邏輯也得到了統一的管理。令人驚喜的是,重構完畢後,程式碼不僅變得條理分明,行數反而精簡了兩百多行。這種乾淨、低耦合的結構,讓後續的功能擴展變得輕鬆許多。


2. OCR 的紅色濾鏡「辨識幻覺」與效能微調

在上一篇日誌中,我曾提到為了提升 PACS 畫面上 Series Number 的 OCR 辨識成功率,我自作聰明地設計了「紅色虛擬濾鏡(CaptureOcrWithFilter)」,在截圖瞬間於目標區域覆蓋一層半透明的紅色 GUI,試圖透過改變對比度來減少數字誤判。

然而,這個設計在實戰中很快就翻車了。

在某些特殊的視窗對比度或字體下,這層紅色濾鏡反而對 OCR 引擎造成嚴重的視覺干擾,甚至引發了荒謬的「辨識幻覺」——它會把原本清晰的數字「4」辨識成奇奇怪怪的中文字。

這就是臨床開發上最真實的血淚。發現問題後,我選擇「去繁從簡」:

  1. 移除紅色濾鏡:果斷廢棄該機制,並將函數重命名為更純粹的 CaptureOcr
  2. 消滅無效延遲:移除了 OCR 截圖前無意義的 Sleep(50),讓抓取反應更即時。
  3. 調整執行順序:確保 OCR 截圖在 F12 除錯框(綠框或紅框)畫到螢幕上之前就完成,徹底避免除錯的輔助視覺元素干擾辨識。

調整之後,不僅抓取速度變快,辨識的穩定度也提升了。


3. 極限臨床場景的突破:影像組偏移與 MPR 補償開關

臨床使用的 Infinitt G3 PACS 系統有許多特殊的設計。在某些重組序列(Sequence)中,影像並非單純的一個大 Series,而是被拆分成好幾個「影像組」(類似子分組或分頁)。此時如果程式只單純抓取畫面上的 Image 編號,得到的數字會跟整套 Series 的真實編號完全對不上。

為了解決這個極限場景,我深入研究了 PACS 的 UI 樹,並在 Pattern Map 中加入了影像組 ComboBox (imgGroup) 的推導欄位。當程式藉由探針(Probe)或 Acc 模式偵測到這類分組序列時,會自動獲取當前影像組的數值與項目數,在背景進行偏移量算定,從而推導出真實的影像編號。

另外,針對之前加入的「Coronal/Sagittal/MPR 自動影像編號 +1 補償」功能,雖然解決了放射師刪除對位影像造成的圖號落差,但在面對少數不需補償的特殊序列時,反而會造成困擾。

因此,我決定把控制權還給當下的讀片情境:在 GUI 主介面以及系統托盤(TrayMenu)同步加入了一個實體的 EnableMprImgOffset Checkbox(影像補償開關)。需要時打勾,不需要時即時關閉,臨床彈性大增。


4. 臨床工作流的拼圖:結節剪貼簿匯入

在日常撰寫報告時,常會遇到「需要修改或繼續編輯前一次複製出來的結節資料」的情況。例如,我昨天用 NoduleTracker 抓好並貼在報告裡的格式是 RUL:15;22; LUL:10,今天病人做完比對後,我想把這筆資料重新載入 GUI 裡,以便繼續追加新的結節或進行編輯。

如果只能一筆一筆手動輸入,那自動化的價值就打折了。

於是我開發了「Import Clipboard」(匯入剪貼簿)功能。它會自動解析剪貼簿中特定的 Lobe:Img 格式字串,將未知的 Series 預設為常規 Lung window 的 Series 4。在匯入時,程式還會自動比對既有資料,聰明地略過肺葉、Series 與 Image 完全相同的重複項目。

這個一鍵無縫回填的機制,成為了我近期跨工作站編輯報告時最愛的「神功能」。


5. 多螢幕 DPI 自適應與提示元件重構

放射科醫師的日常離不開螢幕。在診斷室裡,我們常常是一邊看著 3MP 或 5MP 的醫療專用診斷螢幕,另一邊用普通 1080p 螢幕打報告。這種多螢幕且解析度、DPI 截然不同的環境,經常會讓 AHK 產生的 GUI 視窗或 ToolTip 發生跑版或大小失常的問題。

這季我將全域的提示訊息元件統一重構為 G3PacsNotify,並在背後做了多螢幕 DPI 自適應的計算。現在,不論我的 PACS 視窗被拖到哪一個螢幕,自動化抓取成功時的提示框都能以最合適的比例與動態高度顯示,再也不會因為跨螢幕而字體縮成一團或超出邊界。


6. 架構的終極解耦:G3PacsProbe 共用模組的誕生

隨著自己寫的 PACS 輔助腳本越來越多,除了主力的 NoduleTracker.ahk,還有其他幾組負責不同快速鍵重映射的腳本。我發現,這些腳本在背後都必須去執行一件事:偵測並匹配 G3PACS 的視窗控制項

原本,每個腳本都各自複製了一份探針(Probe)匹配規則與空間幾何驗證(Spatial Match)邏輯。這帶來了極大的維護隱憂——萬一哪天醫院的 PACS 系統升級,導致 ClassNN 或 UI 結構改變,我必須把所有腳本翻出來一個一個修改。

在 6 月底,我下定決心進行了二次重構:將所有的探針 Pattern 定義、Series 匹配文字驗證、以及空間幾何驗證等邏輯,徹底抽離出來,建立了一個獨立的共用模組 Lib/G3PacsProbe.v2.ahk

現在,NoduleTracker.ahk 只需要簡單地 #Include <G3PacsProbe.v2>,直接呼叫 G3PacsProbe 類別的靜態方法即可。這不僅精簡了主程式的複雜度,實現了 DRY (Don’t Repeat Yourself) 原則,也為未來開發新的 PACS 自動化工具打下了堅實的底座。


結語

這三個月的開發過程,就像是在繁忙的臨床實務與程式碼架構之間跳著華爾滋。每一次在診斷空檔進行的重構與 Bug 修正,都是為了讓自己在面對堆積如山的 CT 影像時,能更專注於診斷本身。

工具越是隱形、越是順手,就代表自動化的價值越是成功。下個季度,期待 NoduleTracker 能陪伴我走過更多個值班的夜晚。


程式碼

  1. NoduleTracker.ahk
  2. Lib/G3PacsNotify.v2.ahk
  3. Lib/G3PacsProbe.v2.ahk


Leave a Reply