2025年8月20日

imagej課程:啟


今天一口氣貼了很多 imagej的課程文章,這是有原因的。

因為這是我最近在國防醫學大學開的一系列工作坊的教材啊!是用imagej做生醫影像處理的工作坊。

怎麼會找去開課?那是因為邀約的老師當初在國外念博士的時候,為了要做影像處理,然後就到YT上找,結果就看到了我那一系列教學影片。後來他任教時,因為學校有這方面的課程需求,所以就來邀約找我囉。

雖然我過去已經寫了不少blog文章,也有很多教學影片,但由於課程是好幾週的連續性課程,又是針對醫學院的師生,所以我還是從頭開始寫講義教材。如果有興趣學的,也可以自己看看囉,雖然內容很多,但其實多數使用者的需求都只要會用一點點就夠了喔。

其實如果要完整閱讀的話,到github去讀會比較好喔。

imagej課程:imagej的影像分析方法學流程


1. 明確分析目標

  1. 定義分析需求:要從影像中提取哪些資訊?(例如細胞數量、粒線體分布、結構形態等)
  2. 設定量化指標:確定衡量標準,方便後續驗證結果。
  3. 詢問生成式 AI,獲取相關資訊與建議。

2. 學習工具使用

  • 參考官方文件
  • 觀看教學影片或範例
  • 有些plugin沒有提供文件,如何找到操作方法:
  • 查看 plugin source code,使用quick search功能,搜尋功能後點選source,會連到github。

生成 Macro

  • 使用 ImageJ 的 Macro 語言撰寫自動化腳本,利用使用生成式 AI 工具(如 ChatGPT)生成 ImageJ Macro
  • 根據需要調整 Macro 以符合特定分析需求
  • 將 macro 參數化,例如:將影像路徑、分析參數等設為變數,方便重複使用

imagej課程:ImageJ 自動化與巨集程式設計


巨集語言介紹

ImageJ使用一種簡單的內建腳本語言,稱為 ImageJ Macro Language

  • 它具有基本的程式結構,包括變數、運算子、條件判斷和迴圈。
  • 主要用於呼叫ImageJ的選單指令、操作影像窗口、讀取和寫入數據。

巨集錄製

ImageJ提供了一個方便的巨集錄製器,可以將手動操作轉換為巨集程式碼。

  • 錄製器會記錄您在選單中執行的大多數操作以及一些對話框互動。
  • 這是學習巨集語法和了解特定操作對應的指令的絕佳方式。

在ImageJ中錄製巨集:

  • 開啟 Plugins > Macros > Record...
  • 錄製窗口會彈出,顯示正在記錄的指令。
  • 執行您想要自動化的手動步驟(例如:開啟影像、調整亮度/對比度、套用濾波器、執行分析)。
  • 執行完畢後,點擊錄製窗口中的 Create 按鈕,將記錄的程式碼輸出到一個新的巨集編輯器窗口。
  • 點擊 Close 停止錄製。
  • 錄製的程式碼可以在巨集編輯器中進行修改和調整。可以編輯參數、加入流程控制或使用者互動。

基本語法

ImageJ Macro Language 的語法類似於C語言或其他腳本語言,但更簡化。 - 變數無需顯式宣告類型,直接賦值即可。 - 常見的運算子(+、-、*、/、=、>、<、==、!= 等)皆可使用。 - 條件判斷使用 ifif...else 結構。 - 迴圈結構包括 forwhile

範例:基本操作

// ==== 1. 數值類型與變數 ====
var number = 123;
var decimal = 3.14;
var text = "Hello ImageJ";
var array = newArray(1, 2, 3, 4, 5);

print("Number: " + number);
print("Decimal: " + decimal);
print("Text: " + text);

// 列印陣列
print("Array elements:");
for (i = 0; i < array.length; i++) {
    print(array[i]);
}


// ==== 2. 算術運算 ====
var a = 10;
var b = 3;

sum = a + b;
difference = a - b;
product = a * b;
quotient = a / b;

x = 5;
y = 7;
x += 1; // x = 6
y *= 2; // y = 14

print("Sum: " + sum);
print("Difference: " + difference);
print("Product: " + product);
print("Quotient: " + quotient);
print("x after +=1: " + x);
print("y after *=2: " + y);

// ==== 3. 邏輯運算 ====
var value = 75;
var threshold = 50;

if (value > threshold) {
    print("Above threshold");
}

var x_val = 10;
var y_val = 20;

if (x_val > 0 && y_val < 100) {
    print("Within range");
}

if (x_val < 0 || y_val > 100) {
    print("Out of range");
} else {
    print("Safe range");
}

函數與程序

  • ImageJ巨集語言提供了大量的內建函數和程序(指令)。
  • 內建函數: 用於執行特定的操作,例如數學計算、字串處理、檔案操作、獲取影像資訊等。它們通常有返回值。
  • 程序(指令): 大多數對應ImageJ的選單命令或對話框操作。它們執行一個動作,通常沒有返回值。可以使用run() 命令或直接使用指令名稱調用。
  • 自定義函數: 您可以編寫自己的函數來組織程式碼和重用邏輯。

範例


// 建立測試影像
newImage("Test", "8-bit black", 256, 256, 1);
print("Image created: " + getTitle());

// 獲取影像尺寸
width = getWidth();
height = getHeight();
print("Width: " + width + ", Height: " + height);

// 設定與讀取像素值
x = 100;
y = 100;
setPixel(x, y, 255); // 設定像素為白色
value = getPixel(x, y); // 讀取像素值
print("Pixel value at (" + x + "," + y + "): " + value);

// ==== 2. 用戶交互 ====

// 對話框輸入數字
Dialog.create("Input Example");
Dialog.addNumber("Value:", 0);
Dialog.show();
userValue = Dialog.getNumber();
print("User entered value: " + userValue);

// 文件選擇
filePath = File.openDialog("選擇檔案");
print("你選擇的檔案: " + filePath);

範例:使用者動作批次處理每一個slice


// ================================
// ImageJ Macro 範例:生成 Stack 並分析每個 slice
// ================================

macro "Generate Stack and Analyze" {

    // ==== 1. 生成 Stack ====
    width = 256;
    height = 256;
    n = 5; // Stack 幀數

    newImage("StackExample", "8-bit black", width, height, n);

    // 填充每一幀測試數據 (隨機亮點)
    for (i = 1; i <= n; i++) {
        setSlice(i);
        for (j = 0; j < 100; j++) { // 100 個隨機亮點
            x = floor(random() * width);
            y = floor(random() * height);
            setPixel(x, y, 255);
        }
    }

    print("Stack created with " + nSlices + " slices.");

    // ==== 2. 設置測量參數 ====
    run("Set Measurements...", "integrated display redirect=None decimal=3");

    // ==== 3. 對每一 slice 分析 ====
    waitForUser("圈選區域");        
    setTool(0);

    for (i = 1; i <= n; i++) {
        setSlice(i);                

        run("Measure");
    }

    print("Stack analysis completed.");
}

使用者互動

巨集可以與使用者進行互動,例如顯示訊息、請求使用者輸入參數。 這使得巨集更加靈活,可以適應不同的影像和需求。

  • 訊息提示: 使用 print() 函數將訊息輸出到Log窗口;使用 showMessage()showMessageWithCancel() 彈出訊息對話框。
  • 參數輸入: 使用 Dialog.create() 創建自定義對話框,並使用 Dialog.addNumber(), Dialog.addString(), Dialog.addCheckbox(), Dialog.addCheckbox() 等方法添加輸入控件。最後使用 Dialog.show() 顯示對話框並獲取使用者輸入的值。

範例:使用者互動

// 範例:彈出對話框讓使用者輸入粒子分析的最小尺寸
Dialog.create("粒子分析參數");
Dialog.addNumber("最小粒子尺寸 (pixels):", 100);
Dialog.show();
minSize = Dialog.getNumber();

if (minSize > 0) {
    run("Analyze Particles...", "size=" + minSize + "-Infinity display");
} else {
    print("最小尺寸無效,跳過分析。");
}

範例:文件批次處理

// ===== 主流程 Macro =====
macro "產生粒子範例並測量" {

    // ==== 1. 生成範例影像 ====

    imageN = 5; // 生成 5 張範例影像
    width = 512;
    height = 512;

    imgDir = getDirectory("選擇存檔資料夾");        
    generateSampleImages(imgDir, imageN, width, height);

    // ==== 2. 批次處理生成的範例影像 ====

    files = getFileList(imgDir);

    for (i = 0; i < files.length; i++) {
        if (endsWith(files[i], ".tif")) {
            processFile(imgDir + files[i]);
        }
    }
    // 將 summary 表格輸出到 CSV
    outputDir = getDirectory("選擇選擇要輸出的資料夾");        
    resultsFile = outputDir + "測量結果.csv";    
    saveAs("Results", resultsFile);
}

// ===== 生成範例影像 =====
function generateSampleImages(imgDir, imageN, width, height) {
    for (i = 1; i <= imageN; i++) {
        newImage("Sample_" + i, "8-bit black", width, height, 1);

        // 生成隨機亮點
        for (j = 0; j < 50; j++) { // 50 個亮點
            x = floor(random() * width);
            y = floor(random() * height);
            setPixel(x, y, 255);
        }

        saveAs("Tiff", imgDir + "Sample_" + i + ".tif");
        close();
    }
}

// ===== 測量 =====
function processFile(inputPath) {
    open(inputPath);


    // 測量粒子
    run("Set Measurements...", "area mean min max centroid redirect=None decimal=2");
    run("Analyze Particles...", "size=1-Infinity show=Nothing summarize");
    close();

}

imagej課程:TrackMate plugin 應用指南

教學影片

TrackMate 影像追蹤教學

本教學文章的資料來源:TrackMate version 7 novelties.pdf TrackMate 是 Fiji 影像處理軟體中一個強大且模組化的外掛程式,專門用於自動化追蹤影像中的粒子或物體,並支援手動校正和半自動追蹤。它將追蹤過程分為幾個主要步驟:

  1. 偵測 (Detection)
  2. 過濾 (Filtering)
  3. 追蹤 (Tracking)
  4. 分析/顯示 (Analysis/Display)

1. 環境設定與啟動 TrackMate

啟動 TrackMate :執行 Plugins > Tracking > TrackMate


2. 初始面板:檢查影像校準與維度

  • 空間與時間校準:確認影像的像素大小(例如微米 µm)和幀間時間(例如分鐘 min)是否正確。 如果校準不正確,建議在 TrackMate 之外,透過 Image > Properties 在 Fiji 中修改影像的metadata,然後回到 TrackMate 面板點擊 Refresh source 按鈕來更新資訊。
  • 影像維度:確認影像維度是否正確(例如 2D 序列影像或 3D Z-stack)。
  • 定義處理區域:你可以選擇影像中的一個 ROI (Region of Interest) 來定義 TrackMate 進行偵測的子區域。這有助於加速參數測試,特別是在處理大型影像時。

3. 選擇偵測演算法 (Select a Detector)

TrackMate 提供多種偵測演算法來識別影像中的物體。偵測器負責找出影像中的點(Spots)輪廓,並為其提供基本的數值特徵,例如座標、半徑和品質。

  • DoG detector

    • 檢測圖像中亮點(bright blobs)的檢測器,基於高斯差分的檢測器,計算兩個不同sigma值的高斯濾波器差值來近似LoG濾波器。
    • 特別適合小尺寸點的檢測(< ~5像素)**,計算在直接空間進行,速度較快。
  • Hessian detector

    • 檢測亮點(bright blobs)的檢測器,基於計算圖像的Hessian矩陣行列式來工作。
    • Hessian detector相比LoG detector具有更好的邊緣響應消除能力,特別適合檢測具有強邊緣的圖像中的點。
  • Label-Image detector (標籤影像偵測器):從標籤影像中建立物體。標籤影像中每個物體由不同的整數值表示,這有助於分離接觸的物體。

  • LoG detector

    • 使用拉普拉斯高斯濾波器來檢測blob狀結構,適合檢測各種尺寸的blob狀結構,對於大點檢測或需要高精度表現更好,計算在傅立葉空間進行。
  • Manual annotation

  • Mask detector (遮罩偵測器):從二值化遮罩影像中建立物體。物體由像素值大於 0 的連通區域組成。通常會將遮罩作為原始影像的一個額外通道。

  • Thresholding detector (閾值偵測器):從灰階影像中,根據指定閾值來分割物體。

以下有安裝其他外掛才會出現

  • TrackMate-MorphoLibJ:利用 MorphoLibJ 庫中的 Morphological Segmentation
  • TrackMate-Ilastik
  • TrackMate-StarDist:利用 StarDist 深度學習模型進行細胞核等物體分割
  • TrackMate-Weka:利用 Trainable Weka Segmentation 外掛程式來分割物體

4. 偵測器配置面板

LoG Detector (Laplacian of Gaussian)

  • Target Channel: 選擇要偵測的通道,預設值為1
  • Radius: 預期斑點半徑,預設值為5.0
  • Threshold :品質閾值,低於此值的斑點將被濾掉,預設值為0
  • Median Filtering:是否進行中值濾波預處理,預設為false
  • Sub-pixel Localization : 是否進行亞像素定位,預設為true

DoG Detector (Difference of Gaussian)

  • DoG偵測器與LoG偵測器 使用相同的設定參數

Hessian Detector

  • Target Channel: 目標通道選擇
  • Radius XY : XY方向半徑
  • Radius Z : Z方向半徑,預設值為8.0
  • Threshold: 品質閾值
  • Normalize: 是否標準化品質值到0-1範圍,預設為false
  • Sub-pixel Localization: 亞像素定位

Threshold Detector

  • Target Channel: 目標通道
  • Intensity Threshold: 強度閾值
  • Simplify Contours: 是否簡化輪廓

Label Image Detector

  • 與Threshold Detector設定大部分相同,但不設定強度閾值

Mask Detector

  • Mask Channel:指定遮罩影像所在的通道。例如,如果你的原始影像有兩個通道,第二個通道是遮罩,則選擇 Channel 2。
  • Simplify contours (簡化輪廓):
    • 當偵測器獲得物體輪廓時,勾選這個選項會產生一個更平滑、包含更少線段的簡化形狀。
    • 優點:生成更小的 TrackMate 文件,更重要的是,可以產生更準確的形態特徵,因為像素級的輪廓會高估周長,進而影響相關的形態特徵。
    • 建議在物體足夠大(通常大於 10 個像素)時使用此選項,否則簡化可能導致輪廓不準確。

5. 偵測處理與初始點過濾(Initial thresholding)

  • 初始點過濾 (Initial Spot Filtering)
    • 偵測完成後,會進入「初始點過濾」步驟。
    • 此步驟的目的是在計算所有點的詳細特徵之前,根據「品質 (Quality)」值篩選掉大量不相關的點,以節省記憶體和計算時間。
    • 偵測器會為每個點分配一個「品質」值,反映偵測結果的可靠性。
    • quality是一個數值特徵,反映了detector對該spot檢測結果的信心程度。較高的quality值通常表示該spot更可能是真實的目標物體而非噪聲。不同的detector會用不同的方法計算quality,但都遵循"越高越好"的原則。你可以根據品質的直方圖手動設定一個閾值。低於此閾值的點將被完全丟棄。
    • 對於大多數簡單的案例,可以將閾值條保持在接近 0 的位置

6. 選擇顯示方式

此面板讓你選擇追蹤結果的顯示方式:

  • HyperStack Displayer :將追蹤結果非破壞性地疊加在 Fiji 的影像堆棧視窗上。建議選擇此模式,因為它更輕量、更簡單,並且允許直接在影像上進行手動編輯。

7. 點過濾 (set filter on spot)

這個面板允許你根據偵測到的點的數值特徵(例如大小、形狀、位置或訊號強度)來進一步篩選點。

  • 添加過濾器:點擊綠色 + 按鈕來添加一個新的過濾器。
  • 選擇特徵:從下拉選單中選擇你想要過濾的特徵,例如 Area (面積)、Mean intensity (平均強度) 或 Circularity (圓度)。
    • 範例:如果你的影像中有許多小雜訊點,你可以添加一個 Area (面積) 過濾器,並設定為 Above (大於) 一個特定值,以移除過小的物體。
  • 調整閾值:你可以直接在直方圖中拖曳閾值條,或者在文字欄位中輸入精確值。影像中的顯示會即時更新。
  • 你可以堆疊多個過濾器,TrackMate 會取交集保留滿足所有條件的點。

8. 選擇追蹤演算法 (select a tracker)

此面板讓你選擇粒子追蹤的演算法,即「追蹤器」(Tracker)。追蹤器會將偵測到的點連結起來,形成完整的軌跡 (Tracks)。

  • LAP trackers:LAP 追蹤器,基於線性分配問題 (LAP,Linear Assignment Problem)。適用於布朗運動的粒子,在粒子密度不高時也適用於非布朗運動。

    • Simple LAP tracker (簡單 LAP 追蹤器):處理間隙閉合 (gap-closing) 事件(粒子在某個frame消失,到幾個frame之後又出現),不處理粒子分裂 (splitting)或合併 (merging) 事件。連結成本僅基於點之間的距離。
    • LAP tracker (LAP 追蹤器):允許偵測所有類型的事件,包括間隙閉合、分裂和合併事件。可根據物體特徵值差異來調整連結成本。
  • Kalman tracker:基於Kalman filter去預測等速粒子移動的軌跡。

    • 能夠處理 occlusion(遮擋事件),例如被其他細胞遮擋。
    • Kalman filter 建立的是「動態模型」,預測物件在無觀測時的合理位置。即使某些影格沒有偵測到實體,Kalman 仍能依據上一狀態與速度估計,持續推進軌跡。能容忍短暫消失的物件或是掃描過程中的 detection failure。
  • Advanced Kalman tracker
  • The Overlap tracker: 適用於複雜的形狀且有限的移動速度,基於圖像中物件的空間重疊程度(pixel/region overlap)來建立軌跡,
  • The Nearest-Neighbor tracker:最近鄰居搜索追蹤器,此幀中的每個物體連結到下一幀中最近的物體。

9. 追蹤器配置面板

LAP 追蹤器參數

  • Frame to Frame linking (幀到幀連結)
    • Max distance (最大距離):設定在兩幀之間連結兩個物體的最大允許距離。如果兩個點之間的距離超過此值,它們將不會被考慮連結。
    • Feature penalties (特徵懲罰)
  • Gap closing (允許間隙閉合)
    • Allow gap closing (允許間隙閉合)勾選此選項,允許軌跡在物體短暫消失後重新連結。
    • Max distance (最大距離):間隙閉合的最大距離。
    • Max frame gap (最大幀間隙):物體消失的最大幀數,超過此幀數將不會被連結。
  • Track splitting (允許軌跡段分裂)
    • Allow track segment splitting勾選此選項以偵測分裂事件,例如細胞分裂。
    • Max distance (最大距離):分裂事件的最大距離。
    • Feature penalties for splitting
  • Track merging (允許軌跡段合併)
    • Allow track segment merging勾選此選項以偵測合併事件。
    • Max distance (最大距離):合併事件的最大距離。
    • Feature penalties for merging
  • Feature penalties (特徵懲罰):可以根據物體的特徵值差異來調整連結成本,例如懲罰平均強度差異大的連結。tracker在連接spots時不僅考慮空間距離,還能根據物體的特徵差異來調整連接成本。 TrackerKeys.java:83-96 這些特徵可以包括亮度、大小、形狀等物理屬性。當兩個spots的特徵差異較大時,連接成本會相應增加,使tracker傾向於選擇特徵相似的spots進行連接。在實際使用中,如果沒有設定feature penalties,系統會回退到使用純距離的成本函數。

Simple LAP參數

  • Linking max distance (連接最大距離)
  • Gap-closing max distance (間隙閉合最大距離)
  • Gap-closing max frame gap (間隙閉合最大幀間隔)

Kalman Tracker / Advanced Kalman Tracker參數

Kalman濾波器的設定

  • Initial search radius (初始搜索半徑)
  • Search radius (搜索半徑)
  • Max frame gap (最大幀間隔)
  • Feature penalties
  • Splitting和merging設定

Nearest Neighbor Tracker參數

  • Maximal linking distance (最大連接距離)

10. 軌跡過濾 (set filter on tracks)

追蹤完成後,你會進入「軌跡過濾」面板,可以根據軌跡的屬性(例如長度、速度或位置)移除不相關的軌跡。你可以添加多個過濾器,例如 Track duration (軌跡持續時間),設定一個閾值來移除過短的軌跡(例如,移除那些進出視野的細胞)。


11. 顯示選項 (Display Options)

此面板讓你自訂點和軌跡的顯示方式。

  • Display spots (顯示點)as ROIs (作為 ROI):勾選這些選項以顯示偵測到的物體及其輪廓。
  • Color spots by (點的顏色依據):你可以根據點的任何數值特徵,例如 Mean intensity (平均強度) 或 Area (面積) 來設定其顏色,以便視覺化不同特徵值的點。
  • Display tracks (顯示軌跡):勾選此選項以顯示軌跡。
  • Show tracks (軌跡顯示模式):你可以選擇軌跡的顯示模式,例如 Show tracks forward in time (向前顯示軌跡),這會顯示物體未來的移動軌跡。
  • Color tracks by (軌跡的顏色依據):你可以根據軌跡的任何數值特徵,例如 Total distance travelled (總移動距離) 或 Track mean speed (軌跡平均速度) 來設定其顏色。
  • 點擊 Edit settings (編輯設定) 可以進一步調整顯示選項,例如繪製填滿的點 (draw spots filled) 或線條粗細 (line thickness)。

12. 匯出結果 (Export Results)

在「顯示選項」面板的底部,你通常會找到匯出結果的按鈕。

  • 匯出 CSV 文件:點擊 Tracks (軌跡) 按鈕,你可以選擇匯出 Spots (點)、Edges (連結) 和 Tracks (軌跡) 的數值特徵資料為 .csv 文件。這些文件可以用於其他軟體(如 MATLAB)進行進一步分析。

13. 繪製特徵圖 (Plot Features)

此面板允許你將點、連結或軌跡的任何數值特徵繪製成圖表。

  • 選擇 X 軸和 Y 軸特徵:例如,你可以將 T (時間) 作為 X 軸,Area (面積) 或 Circularity (圓度) 作為 Y 軸,以觀察細胞大小或形狀隨時間的變化。
  • 你可以同時繪製多個 Y 軸特徵。
  • 點擊 Plot features (繪製特徵) 按鈕生成圖表。右鍵點擊圖表可以匯出為 PDF、PNG、SVG 影像或 CSV 數據。

14. 執行動作 (Actions)

這是 TrackMate 工作流程的最後一個面板,你可以在此執行各種最終操作。

  • Capture overlay (捕捉疊加影像):從下拉選單中選擇此動作,可以將追蹤結果疊加到原始影像上,並匯出為視訊或靜態影像。
    • 選擇此動作後,點擊 Execute (執行),彈出視窗中你可以定義要保存的時間間隔。TrackMate 將生成一個帶有追蹤疊加的視訊。
    • 記得將生成的影像/視訊保存到你的電腦上 (File (檔案) > Save as...)。

15. 手動編輯 (Manual Editing)

即使自動追蹤的結果很好,在複雜情況下仍可能需要手動校正。

  • TrackMate 允許你手動建立、編輯、移動或刪除點和連結,以及調整點的半徑。
  • 在 HyperStack Displayer 中編輯點:
    • A 鍵:在滑鼠位置新增一個點。
    • D 鍵:刪除滑鼠下的點。
    • Space (按住) + 滑鼠移動:移動滑鼠下的點。
    • Q / E 鍵:減小 / 增大點的半徑。
  • 在 HyperStack Displayer 中建立/刪除連結:
    • 選擇兩個點 (Shift + Click),然後按下 L 鍵可以建立或刪除它們之間的連結。
  • TrackScheme 工具:TrackScheme 是一個專門用於軌跡可視化和編輯的工具,它以分層圖的形式顯示軌跡,特別適合編輯細胞譜系。你可以從「顯示選項」面板啟動它。


教學範例

範例影像

C.elegans胚胎發育

  • 此影像是C. elegans 胚胎影像,是從一個更長的影片中擷取的最大強度投影 (MIP)。
  • 此影像有兩個通道:
    • 第一個通道:包含原始影像資料,顯示經過 eGFP-H2B 染色並在雷射掃描共焦顯微鏡下成像的 C.elegans 胚胎螢光。可以看到細胞核的移動和分裂,以及兩個較小的極體。
    • 第二個通道:包含透過以下步驟處理後的訊號分割結果:
      1. 中值濾波 (Median filter)
      2. 高斯濾波 (Gaussian filter)
      3. 簡單的閾值處理 (Plain thresholding)
  • 使用Mask Detector
  • 使用LAP tracker
    • 因為能夠處理分裂事件 (split events) 的偵測。極體可能會出現錯誤的分裂,其被錯誤地連接到頂部細胞的影片。可以手動糾正,或根據面積篩選極體。
    • Frame to Frame linking (幀間連結):設定兩個物體之間連結的最大距離,對於本範例影像,使用 20 (microns)。
    • Allow gap closing (允許間隙閉合):勾選此方框。設定 Max distance (最大距離) 為 20 微米,Max frame gap (最大幀間隙) 為 5。
    • Allow track segment splitting (允許軌跡片段分裂):勾選此方框(例如,因細胞分裂引起)。設定 Max distance (最大距離) 為 20 (microns) 。

cell migration

  • 使用thresholding detector
  • LAP tracker
    • Frame to Frame linking :maximum distance to link two objects between frames:20 microns.
    • Allow gap closing box : Max distance: 20 microns and Max frame gap: 4.
    • Allow track segment splitting and insert value Max distance: 20 microns.
    • untickedB Track segment merging

Tracking label images

  • 使用 label image detector
    • in frame 65 you will see small floating cells that were segmented. add a spot filter to remove anything with an Area lower than 230.
  • LAP tracker
    • Max distance: 20 microns and Max frame gap: 5.
    • Allow track segment splitting and insert value Max distance: 30 microns.

腦膜炎雙球菌的細胞生長Neisseria meningitidis bacterial growths

  • 使用 trackmate-ilastik
  • LAP Tracker

爪蟾Xenopus的細胞

  • 使用trackmate-morpholibj
  • Overlap tracker(直徑大於移動距離,很大顆慢慢走)

癌細胞

  • 使用trackmate-stardist
  • LAP tracker

乳癌細胞

  • 使用 trackmate-cellpose
  • 使用 Overlap tracker 優於 LAP tracker,因為細胞往下移動,而有些細胞會從影像上方出現。LAP 可能會誤認為這些新細胞是某個在其下方的細胞「剛剛分裂」所產生的子細胞,結果會導致錯誤的細胞分裂事件。因為LAP 預設以距離最短、分配代價最低為對應依據,不一定能辨認「畫面外進入 vs 真正的細胞分裂」。

膠質母細胞瘤

  • 使用trackmate-cellpose
  • 檔案包括預訓練模型
  • Simple LAP tracker

human dermal microvascular blood endothelial cells expressing Paxillin

  • 使用trackmate-weka
  • 檔案內有 trained Weka classifier

其他

繪製細胞核形狀隨時間的變化

有了細胞形狀及其譜系後,可以追蹤細胞分裂時形狀如何變化。例如繪製底部細胞的細胞核大小和圓度隨時間的變化。

  1. 透過點擊其中一個斑點來選擇底部細胞。
  2. 然後移至 TrackMate 精靈的 Plot feature (繪製特徵) 面板。確保你位於 Spots (斑點) 標籤頁。
  3. 在此面板中,在 Feature for Y axis (Y 軸特徵) 的第一個列表中選擇 Area (面積)
  4. 點擊綠色的 + 按鈕以添加第二個特徵列表,然後選擇 Circularity (圓度) 特徵。
  5. 你希望僅繪製所選斑點的軌跡 (track) 的這些特徵值。為此,請選擇底部的 Tracks of selection (所選軌跡) 單選按鈕。當然,感興趣軌跡中的至少一個斑點必須被選中。
  6. 點擊 Plot features (繪製特徵) 按鈕。會出現兩個圖表。
  7. 頂部圖表顯示面積隨時間的變化。可以看到它穩定增加直到細胞在 t=15 分鐘時分裂。面積急劇下降,並且圖表中現在繪製了兩個細胞。它們的面積恢復增加,且速率幾乎相同。
  8. 圓度繪製在第二個圖表中。它幾乎一直保持很高(接近 1),因為細胞核的形狀大致為球形。當細胞分裂時,細胞核呈現拉長的形狀,導致圓度較低。
  9. 如果你右鍵點擊任何一個圖表,會彈出一個選單,可以將圖表匯出為 PDF、PNG 或 SVG 影像,或將其資料顯示在可保存為 CSV 檔案的表格中。

處理觸碰的細胞 (Mask 編輯)

  1. 有一些觸碰的細胞被錯誤地識別為一個物體,直接編輯Mask進行修復。
  2. 回到 TrackMate 精靈的第一個面板。
  3. 在影像顯示區,選擇有問題的時間點(例如,在 C.elegans 教學中是第 9 幀),處理第二個通道。
  4. 放大有缺陷 Mask 的細胞核。
  5. 在 ImageJ 工具欄中,選擇線段工具。
  6. 雙擊顏色選擇工具,並選擇黑色作為前景色。
  7. 在細胞核和極體之間繪製一條黑線,作為切割
  8. 重複之前的工作進行追蹤。

imagej課程:研究細胞的突起,例如神經纖維

github閱讀版

安裝

SNT 目前是透過 Fiji 的 Neuroanatomy 更新站點進行分發。

第一次從 Fiji 選單 (Plugins › Neuroanatomy › SNT) 啟動 SNT 時,系統應該會提示自動下載所需的相依套件。如果沒有出現提示:

  1. 執行 Fiji (Help › Update…)。
  2. 點擊 Manage update sites
  3. 搜尋並勾選 Neuroanatomy 更新站點。
  4. 點擊 Apply changes 並重新啟動 Fiji。

自動追蹤

  1. 建立二值化影像,並圈選出細胞本體,然後開啟SNT,如果合要求,自動會問是否進行自動追蹤。
  2. 若無,則在SNT視窗執行File > Autotrace Segmented Image..進行設定
  3. 若要更改參數重作trace,則執行SNT的Utitlities > Extract Paths from Segmented Image...

手動追蹤

1. 開始一條新路徑

步驟 I:選擇起點

  • S 鍵: 切換游標自動吸附功能。預設情況下,游標會自動吸附到附近最亮的像素。若要手動控制節點位置,可以按 S 鍵關閉此功能。
  • 左鍵點擊: 在影像中找到路徑的起點,點擊左鍵來標記它。

步驟 II:選擇後續點

  • 左鍵點擊: 移動到同一結構上的下一個點,點擊左鍵。SNT 會自動搜尋這兩點之間的路徑。
  • CEsc 鍵: 若自動搜尋進度不佳,可以按 CEsc 取消搜尋,然後選擇一個離起點更近的點重新嘗試。
  • Z 鍵(在 Cursor Auto-snapping 面板中設定): 將 Z 值增加到大於 0,可以讓游標在移動時自動在 Z 平面進行導航,幫助你找到最亮的體素。

步驟 III:確認臨時路徑

  • Y 鍵: 當 SNT 找到路徑後,會顯示為青色(臨時路徑),並詢問是否確認。如果路徑符合預期,按 Y 確認。確認後,路徑會變成紅色。
  • N 鍵: 如果路徑不正確,按 N 拒絕,程式會回到上一步,讓您重新選擇後續點。
  • F 鍵: 當您完成這條路徑的追蹤後,按 F 結束路徑。完成的路徑會顯示為洋紅色,程式回到步驟 I,準備開始新路徑。

小提示: 熟練後,您可以在 Options 選項卡下的 Temporary Paths 區塊中關閉臨時路徑的確認步驟,以加快追蹤速度。

2. 從現有路徑分岔

步驟 I:選擇要分岔的路徑

  • G 鍵: 將滑鼠游標移到目標路徑附近,然後按 G 來選中它。選中後,路徑會顯示為預設的綠色。
  • 右鍵 → Select Paths by 2D ROI 在影像上畫一個粗略的 2D 範圍,選取範圍內的路徑。
  • 路徑管理器 (Path Manager): 直接在路徑管理器中點擊選取目標路徑。

步驟 II:選擇分岔點

  • Alt + Shift + 左鍵點擊: 按住這兩個鍵,將滑鼠移到分岔點,你會看到游標變成一個帶有「Fork Point」標註的紅色十字。在此點擊左鍵,即可強制在新路徑的起點建立分岔。
  • 右鍵 → Fork at Nearest Node 另一種方式是放大到分岔點,然後右鍵點擊影像,從右鍵選單中選擇此選項。

步驟 III:延伸路徑

一旦選定分岔點,就可以像追蹤新路徑一樣,依照上述步驟繼續延伸路徑(建立臨時路徑並確認)。當您完成這條分岔路徑時,在路徑管理器中會看到它被記錄為原始路徑的「子路徑」。

小提示: 您也可以在 Options 選項卡下的 Temporary Paths 區塊中簡化分岔的快速鍵組合。

精準點位放置

本方法要求 XY、ZY 和 XZ 視圖都可見,以實現精確定位。

  1. 尋找大致位置: 在 XY 視窗中移動滑鼠,按住 Shift 鍵同步所有視圖。
  2. 啟用自動吸附:Main 標籤頁中啟用「游標自動吸附」,讓游標自動吸附到局部最大值。紅色十字游標會標示最有可能的位置。
  3. 放大:+ 鍵放大,所有視窗都會以游標位置為中心放大。每次放大後,請確保游標仍停留在目標結構上。您可以在 Options 選項卡的 Views 元件中調整是否同步所有視圖的縮放。
  4. 定位中心:
    • 如果自動吸附已啟用,只需將滑鼠懸停在結構上。
    • 否則,在每個視窗中移動滑鼠並使用滾輪,同時按住 Shift 鍵同步視圖。
  5. 常用快捷鍵:
    • S 鍵: 隨時按 S 可切換自動吸附。
    • M 鍵:M 可「點擊」體素列中最亮的體素。
  6. 開始路徑: 在滿意的點位上點擊滑鼠左鍵。
  7. 精修: 追蹤完成後,可在路徑管理器中使用 Refine/Fit › Fit Path... 選項,將路徑對齊到結構的中線。

在舊版 3D 查看器中追蹤

舊版 3D 查看器允許在 3D 場景中進行追蹤。

  1. 啟動查看器: 在 SNT 對話框的 3D 選單中,選擇 Legacy 3D Viewer。在 Viewer 下拉選單中選擇 New with image… 並按下 Apply
  2. 追蹤與導航:
    • 追蹤模式: 在 ImageJ 工具列中按 W 鍵激活「魔術棒工具」,然後在 3D 場景中點擊。追蹤方式與 2D 相同。
    • 分岔: 像 2D 畫布一樣,按住 Alt + Shift 進行分岔。
    • 導航模式:H 鍵激活「手形工具」來與場景互動。
    • 旋轉: 按住滑鼠中鍵並拖曳。如果手形工具激活,可使用左鍵拖曳。
    • 平移: 按住 Shift + 滑鼠中鍵並拖曳。如果手形工具激活,可使用 Shift + 左鍵拖曳。
    • 縮放: 使用滑鼠滾輪。
    • 提示: 3D 查看器無法識別 2D 畫布的右鍵選單,例如 Path Editing

合併/連接路徑 (Merging/Joining Paths)

您可以在 Edit Mode 中合併或連接兩條路徑。

  1. 進入編輯模式: 選擇一條路徑,在影像畫布上右鍵點擊,選擇 Edit Mode
  2. 激活合併節點: 將滑鼠懸停在要合併的第一個節點上。
  3. 選擇第二條路徑:G 鍵選擇第二條路徑,並懸停在第二個合併節點上。
  4. 執行合併: 打開右鍵選單,從 Connect To (Start Join)Connect To (End Join) 選單中選擇第一條路徑。

重要提示: - 只有當至少一個節點是末端節點時才能合併,以避免創建循環。 - 合併方向從父路徑到子路徑。如果方向錯誤,SNT 會自動重新定向。 - 禁止創建循環連接。 - 推薦使用路徑管理器 (Path Manager) 中的 Edit 選單來合併或連接路徑。

如何獲取所有突起的長度

在 SNT 中,要獲取所有突起(或稱分支、枝芽)的長度,您主要會使用「Measurements (測量)」功能。SNT 提供了多種方式來進行測量,具體取決於您是想測量整個細胞的突起,還是選定部分路徑的突起。

測量完整細胞的突起長度 (Cell-based Measurements)

如果您想測量一個完整的、已經重建好的細胞(SNT 稱之為「connected component」,即有根的樹狀結構)的所有突起長度,可以這樣操作:

  1. 開啟 SNT 主介面: 確保您的 SNT 插件已啟動。
  2. 選擇命令:
    • 在 SNT 的主對話框中,點擊選單列的 Analysis › Measure…
    • 或者,如果您正在使用 Reconstruction Viewer (重建查看器),則點擊 Analyze & Measure ›
  3. 配置測量對話框:
    • 這會開啟一個「Measurements」對話框。
    • 在這裡,您可以搜尋和選擇您感興趣的指標。對於「所有突起的長度」,您通常會尋找類似於 Cable Length (纜線長度)Total Length (總長度) 這樣的指標。
    • 您還可以選擇渲染測量過的細胞,並匯總現有的測量結果。
    • 透過「齒輪」選單 (Gear menu),還可以訪問離線指南。
  4. 執行測量: 確認您的選擇後,點擊對話框中的按鈕(通常是 OKMeasure)來執行測量。SNT 會輸出一個表格,其中包含您選擇的所有指標的數據。

測量選定路徑的突起長度 (Path-based Measurements)

如果您只想測量 Path Manager 中選定的一組路徑(例如,您只對某個特定區域或特定分支的枝芽長度感興趣),則可以透過 Path Manager 進行操作:

  1. 開啟 Path Manager: 確保您的 Path Manager 視窗已開啟,並顯示您的重建路徑。
  2. 選擇/過濾路徑: 在 Path Manager 中,選取(點擊)或過濾出您想要測量的特定路徑。
  3. 選擇命令: 在 Path Manager 的選單中,點擊 Analyze › Measurements
  4. 獲取結果: 這將針對您選定的路徑,生成相應的測量結果。

區分細胞級和路徑級測量的重要性: SNT 區分了這兩類測量是為了提供靈活性: - 路徑級測量可以對任何結構執行,甚至是有循環 (loops) 的結構。 - 細胞級測量要求結構必須是一個圖論樹 (graph-theoretic tree)(即沒有循環,每個節點只有一條通往根部的路徑)。

大部分 SNT 測量指標在 Metrics 頁面有詳細描述。GUI 中可用的測量通常是單一值的指標,而許多其他測量則可以透過腳本來獲取。

快速測量 (Quick Measurements)

SNT 還提供了一個便利的 Quick Measurements 命令:

  • 在 SNT 主對話框的 Analysis 選單中。
  • 在 Reconstruction Viewer 的 Analyze & Measure 選單中。

這個命令會使用預設設定立即檢索常用指標,無需額外的提示。

注意事項

  • 擬合路徑 (Fitted Paths): 有些細胞級測量可能在混合了擬合和未擬合路徑時不可用,因為路徑是獨立擬合的,可能不知道原始的連通性。若遇到這種情況,測量結果可能顯示為 NaN。您可以考慮使用「原地擬合 (Replace existing nodes)」選項來擬合路徑,或使用 Path Manager 的 Edit › Rebuild… 命令來重新計算路徑之間的關係。
  • 統計分析: SNT 可以匯總比較報告和簡單的統計報告(雙樣本 t 檢定/單向 ANOVA),最多支持六組細胞的比較。這在 Comparing Reconstructions 中有詳細描述。

imagej課程:粒線體數量與體積分析與3D Rendering

使用者需求

樣本資訊

  • 樣本名稱: NAc_aligned.tif
  • 來源: 小鼠腦區 Nucleus Accumbens
  • 染色方式: 細胞膜脂質染上重金屬 Osmium tetroxide
  • 影像設備: 掃描電子顯微鏡 (SEM)
  • 影像資訊:
    • Voxel size: 6.5(x) × 6.5(y) × 60(z) nm
    • 切片數量: 111 slices
    • 已用 SIFT 對齊

分析需求

  1. 分割粒線體

    • 目標: 分割出粒線體,並計算各個粒線體的體積。
    • 附圖: (segmentation example) 為粒線體標定範例。
      • 已分割的粒線體: 粉紅色
      • 非粒線體: 紫色
      • 紅箭頭: 尚未分割的粒線體範例
    • 辨認原則:
      • a. 具有黑色框線的圓形或橢圓形,內部似有 cristae 的線條。
      • b. 全黑 (solid black) 的圓形或橢圓形為非粒線體。
      • c. 被更大結構黑框包圍的亦屬粒線體。
  2. 3D 呈現

    • 3D rendering 分割出的粒線體。
  3. 特徵計算

    • 計算粒線體的數量與各別體積。

流程

影像預處理

  1. Image › Stacks › 3D Project...min intensity取得具有完整影像的範圍,再套用到原始stack進行crop

  2. 複製出單一slice,進行FFT,測試產生頻譜圖。在頻譜圖上進行處理,將週期性結構去除,並將頻譜圖轉回空間域。

  3. 將處理後的頻譜圖,利用Image > Adjust > Threshold...進行二值化處理,目標是阻擋的頻率範圍為黑色,允許通過的頻率為白色。

  4. 利用Process › FFT › Custom Filter...套用上述頻譜圖,將原始影像stack中的週期性結構去除。

影像分割

  1. 使用 Plugins › Segmentation › Trainable Weka Segmentation 3D進行處理,class1作為背景或非粒線體,class2作為粒線體。

  2. 使用freehand line tool標註粒線體與背景。

  3. 使用適中寬度的freehand line:設置stroke width為3-5像素,沿著粒線體中心線繪製:這樣可以捕獲粒線體的主要特徵,在多個切片上標註:確保3D結構的完整性。

  4. training後,得到的結果影像為二值化影像。

二值化影像的切割

  1. 使用Analyze › 3D Objects Counter將二值化影像切割成各個粒線體。每個粒線體都會有一個獨立的ID。且可以得到分析表格,其中包含每個粒線體的體積資訊。

  2. 利用Image > Adjust > Threshold...用單一粒線體的ID,並將其轉換為二值化影像。

  3. 此二值化影像與原始影像進行Image › Calculator Plus...,選擇AND運算,將原始影像中非粒線體的部分去除。即可得到分割後的粒線體影像。

3D rendering

  1. 將上述結果影像crop後,利用Plugins › 3D Viewer進行3D重建。可看到分割後的粒線體的立體影像。

imagej課程:使用 t1-header.tif 進行 MRI 影像分割:分離頭骨與腦組織

t1-header.tif 這組 T1 加權的腦部 MRI 影像為範例,學習如何使用 ImageJ/Fiji 進行基礎的影像分割,將感興趣的解剖結構,如腦組織(Brain)和頭骨(Skull),分離出來,並進行 3D 視覺化呈現。

案例介紹與準備工作

認識範例影像 t1-header.tif

這是一套包含 129 張連續切片的 T1 加權 MRI 影像堆疊(Image Stack)。

  • 資料來源: Jeff Orchard, University of Waterloo.
  • 影像特性:
    • 在 T1 加權影像中,不同組織的對比度良好。一般來說,脂肪(如骨髓)呈現高訊號(亮色),腦白質比腦灰質亮,而腦脊髓液(CSF)則呈現低訊號(暗色)。
    • 影像背景(頭部以外的區域)已被設為零,方便我們進行分析。

操作前的建議

  1. 開啟影像: 直接將 t1-header.tif 檔案拖曳至 Fiji/ImageJ 視窗,或使用 File > Open...
  2. 探索影像堆疊:
    • 使用視窗下方的滑桿,可以瀏覽不同的 Z 軸切片。
    • 執行 Image > Stacks > Orthogonal Views 可以同時從三個正交平面(橫斷面、冠狀面、矢狀面)觀察影像,這對於理解 3D 結構非常有幫助。
  3. 使用工具觀察這種有z stack的影像,例如Plugins > 3D viewer或是 Plugints > Volumln Viewer

步驟一:分離腦組織

我們的目標是建立一個只包含腦組織的二值化遮罩 (Binary Mask),你可以先用之前學過的Image > Adjust > Threshold...進行處理,目標是讓腦組織(腦灰質與白質)被完整選取,同時盡可能排除周圍的腦脊髓液和頭骨。如果需要可以再後續用形態學處理來清理空洞與雜訊。

除了上述手動方法外,我們將利用機器學習來進行分割。

使用機器學習進行分割

當腦組織和頭骨的灰階強度非常相似時,單純的閾值分割會失敗。此時,可以用 Fiji 內建的 Trainable Weka Segmentation ,它不僅只靠灰階值,還能學習紋理、邊緣等特徵,分割效果更佳。

  1. 開啟插件與設定:

    • 開啟的 t1-header.tif 影像。
    • 執行 Plugins > Segmentation > Trainable Weka Segmentation
    • 在 Weka 視窗中,點擊 Settings,確認 Training features 中的選項(預設即可)。
    • 點擊 Create new class 建立三個類別,並分別命名為 Brain, Other, Background
  2. 提供訓練樣本 (Training):

    • 標記 Brain: 在 Weka 視窗中選中 Brain 類別。使用 選取工具,在影像的腦組織區域畫幾個小圈,每畫一個就點擊 Add to class 'Brain' 按鈕。技巧: 請在不同的腦區(灰質、白質)和不同的 Z-slice 上都提供樣本。
    • 標記 Other: 選中 Skull 類別,在頭骨的亮色區域畫圈並加入。
    • 標記 Background: 選中 Background 類別,在腦外的黑色區域畫圈並加入。
  3. 訓練與產生結果:

    • 點擊 Train classifier 按鈕進行訓練。右側的預覽視窗會即時顯示分類結果。如果結果不理想,可以增加更多樣本並重新訓練。
    • 對預覽滿意後,點擊 Create result。這會產生一張新的分類結果影像 (classified image)
  4. 從分類結果中提取腦部遮罩:

    • 在產生的分類結果影像上,執行 Image > Adjust > Threshold...
    • 在 Weka 中,第一個類別 (Brain) 的像素值通常是 1。將閾值滑桿的上下限都設為 1,這樣就只選取了腦部。
    • 點擊 Apply,即可得到一張乾淨的 Brain Mask

步驟二:分離頭骨 (Skull Segmentation)

分離頭骨的邏輯很簡單:頭骨 = 整個頭部 - 腦組織

  1. 建立「整個頭部」的遮罩:

    • 回到原始的 t1-header.tif 影像。
    • 再次執行 Image > Adjust > Threshold...
    • 這次,將閾值下限設為 1(或一個非常低的值),上限設為最大值。目標是選取所有非黑色的像素。
    • 點擊 Apply 產生一個包含整個頭部(腦+頭骨)的遮罩。將其命名為 Head Mask
  2. 影像計算 (Image Calculator):

    • 執行 Process > Image Calculator...
    • 在對話框中設定:
      • Image1: 選擇 Head Mask
      • Operation: 選擇 Subtract (減去)。
      • Image2: 選擇我們在步驟一得到的 Brain Mask
    • 點擊 OK
  3. 得到頭骨遮罩:

    • 計算結果就是一張新的影像,其中只剩下頭骨的遮罩。您可以將其命名為 Skull Mask

步驟三:3D 視覺化呈現

現在我們有了各自獨立的 Brain MaskSkull Mask,可以使用 3D Viewer 將它們視覺化。

  1. 啟動 3D Viewer:

    • 執行 Plugins > 3D > 3D Viewer
  2. 加入腦組織表面:

    • 在 3D Viewer 視窗中,點擊 Add > Surface...
    • Image 下拉選單中選擇 Brain Mask
    • Name: 可命名為 Brain
    • Color: 選擇一個您喜歡的顏色,例如灰色。
    • Threshold: 設為 1。
    • Transparency: 設定一個透明度,例如 50%,這樣才能看到內部。
    • 點擊 OK
  3. 加入頭骨表面:

    • 再次點擊 Add > Surface...
    • Image: 選擇 Skull Mask
    • Name: 可命名為 Skull
    • Color: 選擇白色或淡黃色。
    • Threshold: 設為 1。
    • Transparency: 設為一個較低的值,例如 20%
    • 點擊 OK

現在,您應該可以在 3D Viewer 中看到半透明的頭骨包覆著腦組織的立體模型。您可以用滑鼠自由地旋轉和縮放,從不同角度觀察這些結構。

這些產生的遮罩(Masks)不僅可用於視覺化,也可以進行定量分析。例如對 Brain Mask 影像堆疊執行 Analyze > Histogram,並將 Count(像素數)乘以每個體素(Voxel)的體積,就可以估算出總腦容量。

定量分析:計算體積 (Volume Quantification)

計算原理

體積計算的邏輯是:

總體積 = 體素(Voxel)的總數量 × 單一體素的體積

  • 體素 (Voxel): 可以理解為 3D 空間中的一個像素點,它具有長、寬、高。
  • 體素總數量: 在我們的二值化遮罩(如 Brain Mask)中,這就是所有白色像素的總和。
  • 單一體素的體積: 這需要我們對影像進行空間校正,定義每個體素的真實物理尺寸。

根據此 MRI 數據集的Image > Properties...,其體素尺寸為 1.5 mm × 1.5 mm × 1.5 mm

操作步驟

我們將以計算 腦組織體積 為例。。

設定空間校正 (Set Scale)

在進行任何測量之前,必須先讓 ImageJ 知道影像的真實尺度。

  1. 選取 Brain Mask 或任何一張原始影像堆疊。
  2. 執行 Image > Properties... (快捷鍵 Ctrl+Shift+P)。
  3. 在彈出的對話框中,填入已知的體素尺寸:
    • Unit of length: mm
    • Pixel width: 1.5
    • Pixel height: 1.5
    • Voxel depth: 1.5 (這是 Z 軸的尺寸,即切片厚度)
  4. 勾選 Global,這樣此設定會應用到所有開啟的影像。
  5. 點擊 OK

完成後,影像視窗的標題會顯示校正後的尺寸。

計算體素總數並獲得體積

有兩種推薦的方法可以得到體積。

方法 A:使用直方圖 (Histogram)

此方法讓您了解背後的計算過程。

  1. 選取 Brain Mask 影像堆疊。
  2. 執行 Analyze > Histogram (快捷鍵 Ctrl+H)。
  3. 在彈出的 Histogram 視窗中,您會看到一個表格。由於這是二值化影像,只有兩個值:0 (黑色背景) 和 255 (白色前景)。
  4. 找到 Value255 的那一列,其對應的 Count 值就是白色體素的總數量,將這個數字與單一體素體積相乘,就可以得到腦的體積。

方法 B:使用 3D 物件計數器 (3D Object Counter) (更直接)

Fiji 內建的強大 3D 分析工具可以直接給出校正後的體積。

  1. 選取 Brain Mask 影像堆疊。
  2. 執行 Analyze > 3D OC Options 來設定參數,確保 Volume 已被勾選。
  3. 執行 Analyze > 3D Object Counter
  4. 在設定視窗中,將 Threshold 設為一個介於 1-255 之間的值 (例如 128),以確保只計算白色物件。
  5. 點擊 OK
  6. 在彈出的 "3D Results" 表格中,Volume 欄位直接顯示了計算好的體積(單位為 mm³),並且 Voxels 欄位顯示了體素總數,與直方圖方法得到的結果一致。

3D 形態學分析:量化大腦的表面積與複雜度

我們已經學會了如何從 MRI 影像中分割出大腦並計算其體積。然而,體積只是描述一個三維物體最基礎的參數。大腦最顯著的特徵之一是其表面佈滿了複雜的溝(Sulci)與迴(Gyri),這極大地增加了其表面積。

使用 ImageJ/Fiji 來測量更進階的 3D 形態學 (Morphometry) 參數,如表面積 (Surface Area)球形度 (Sphericity),從而量化大腦的結構複雜度。

分析目標與理論背景

球形度 (Sphericity)

球形度是一個用來描述物體形狀有多麼接近完美球體的無因次參數。其值範圍在 0 到 1 之間: - 值為 1: 表示物體是一個完美的球體。 - 值越接近 0: 表示物體形狀越不規則、越扁平或越細長。

其計算公式為:

Sphericity = (π^(1/3) * (6 * Volume)^(2/3)) / Surface Area

從公式可以看出,在體積 (Volume) 相同的情況下,表面積 (Surface Area) 越大的物體,其球形度就越低。對於大腦而言,複雜的溝迴結構使其在有限的顱腔體積內容納了巨大的皮層表面積,因此其球形度會遠低於一個同樣體積的光滑球體。

操作步驟

準備 3D 遮罩

使用在Brain Mask 作為分析對象。

  1. 開啟 t1-header.tif 影像並依照先前教學產生 Brain Mask 影像堆疊。
  2. 觀察空間校正: :影像已經過空間校正 (Image > Properties...,體素尺寸為 1.5 x 1.5 x 1.5 mm)。這一步對於計算真實的物理表面積和體積至關重要。

使用 3D Object Counter 進行分析

  1. 選取 Brain Mask 影像堆疊。
  2. 執行 Analyze > 3D Object Counter
  3. 參數設定:
    • Threshold: 設為一個介於 1-255 的值(例如 128),以確保只計算白色物件。
    • Min. Voxel: 設為一個較大的值(如 1000),以過濾掉可能的微小雜訊。
    • 確保 VolumesSurface areas 這兩個選項都被勾選。
  4. 點擊 OK

結果

分析完成後,會彈出一個 "3D Results" 表格。

  • Volume [mm^3]: 這就是我們之前計算過的大腦體積。
  • Surface [mm^2]: 這就是大腦的總表面積。

使用這兩個值,代入公式計算大腦的球形度。

imagej課程:螢光強度定量-分析細胞核/質的訊號分佈

我們將以 ImageJ 內建的 Fluorescent Cells.tif 範例影像為基礎,學習影像強度的定量。

1. 案例介紹與準備工作

認識範例影像

  1. 開啟影像: File > Open Samples > Fluorescent Cells.tif
  2. 影像資訊: 這是一張牛肺動脈內皮細胞的螢光影像,為一個包含三個8位元通道的合成影像(Composite Image)。
    • 藍色 (Blue): DAPI 染劑,標定細胞核 (Nucleus)
    • 綠色 (Green): Bodipy FL 染劑,標定微管蛋白 (Tubulin),主要分佈於細胞質。
    • 紅色 (Red): Texas Red 染劑,標定絲狀肌動蛋白 (F-Actin),主要分佈於細胞質的細胞骨架。

分析目標

我們的目標是定量分析微管蛋白(綠色通道)細胞核細胞質中的螢光強度。

觀察影像品質

這個影像目前是以「Composite Mode」(合成模式)來顯示,它將多個獨立的灰階通道(每個通道通常指定不同的偽彩色,例如通道 1 為紅色,通道 2 為綠色,通道 3 為藍色)疊加在一起顯示,形成一個合成的彩色影像,方便同時觀察所有通道的訊號,並視覺化它們之間的空間關係(共定位)。雖然它看起來像一個 RGB 影像,但底層的數據仍然是分離的灰階通道。

Image › Color › Channels Tool...可以切換顯示的模式,可以切換成ColorGrayscale模式。

為了分別觀察不同通道的影像品質,請利用Image › Color › Split Channels將影像分成不同通道來分析。

在進行量化影像前,我們必須注意影像的幾項品質:

  1. 是否產生有損壓縮(lossy compression)嗎?
  2. 最高亮度資訊是否已經丟失?
  3. 是否均勻背景?是否偵測器偏移(uniform background / detector offset)?

有損壓縮(lossy compression)

使用放大鏡工具放大影像,是否會看到 8x8的方形偽影(square shaped artifacts)。若有,可能被進行過JPEG 壓縮,因為JPEG是基於 8x8 像素區塊進行壓縮的演算法,每個區塊都會損失各自的高頻訊號,因此彼此區塊會產生不連續的界面,產生明顯區塊邊界。

最高亮度資訊是否已經丟失?

影像採樣時,進入偵測器的光線量過多,超出了偵測器所能線性響應的範圍,因此產生飽和(saturated),這會使得感測器的讀數限制在最大值(例如255),超過這個數字的都會被剪切(clipped),因此會觀察到過度曝光(overexposed)

我們可以針對個別通道進行Analyze > Histogram觀察個別通道的最高像素值的數量(例如pixel value = 255 ),你可以勾選Log,讓數量少的數值也能清楚顯示在直方圖上(Y軸非線性顯示,而是變成對數)。

請注意藍色通道中的直方圖,強度值255的像素數量有108個。(也許真實強度有高於255的,但卻被剪切了)

均勻背景/偵測器偏移

當沒有任何光子進入偵測器,理論上偵測器應該會採樣到0值,但如果產生偵測器偏移(detector offset),則應該是黑色的區域就會產生非零的數值。你可以用兩種方式檢查:

  • 使用工具列的Pixel inspector,觀察應該黑色的部位是否非零。
  • 觀察直方圖,螢光影像中,因為大多數區域沒有螢光,所以強度值為0的像素應該居多。所以在眾數(Mode)應該為零。

請觀察綠色通道的直方圖和另外兩個通道的直方圖差異。

如果影像產生這種offset,則在後續做共定位分析時,需要進行背景減除(Background Subtraction)零偏移校正(Zero Offset Correction / Bias Correction)的,否則會影響一些需要用像素絕對強度來運算的係數,例如Manders係數

如何進行偏移校正

校正的目的是為了去除所有來自非目標分子或環境的光學噪音,突出真實的訊號。(想像一下大家都站在箱子上量身高,最後得到的身高應該如何校正回真實身高?)

操作方式:

  • 手動選擇背景區域:在影像的空白區域(例如細胞周圍沒有螢光的區域)測量平均強度,然後從整個影像中減去這個值。(結果可能產生負值,但因為是8-bit影像,所以最小值會成為0)

    1. 使用矩形選區工具,選取一個足夠大的背景區域。Analyze > MeasureCtrl+M 來獲取該區域的平均像素值。
    2. 使用Process > Math > Subtract...扣除該數值
  • 使用內建的背景分離Process > Subtract Background...

  • 拍攝背景影像:拍攝一個不含目標染料但具有所有其他樣品成分和培養條件的空白樣品影像,然後從實驗影像中減去它。

    1. 拍攝多張空白影像,然後將這這些影像堆疊起來,計算它們的平均值(Image > Stacks > Z Project...,選擇 Average)。這張平均影像就是你的「偏置主幀 (Master Bias Frame)」。
    2. 使用Process > Image Calculator...,操作選擇 Subtract個通道分別拍攝和減除。

設定測量參數

在開始分析前,先設定需要測量哪些數據。

  1. 執行 Analyze > Set Measurements...
  2. 勾選以下重要參數:
    • Area: 物件的面積。
    • Mean gray value: 訊號的平均強度。
    • Integrated Density: 訊號的總量(= Area × Mean gray value)。
    • Display label: 在結果中顯示影像標籤,方便識別數據來自哪個影像。
  3. 點擊 OK

1.定義細胞核區域

DAPI的藍色通道有清晰的細胞核輪廓,可以用來定義細胞核的選區 (ROI)。

  1. 分離通道::執行 Image > Color > Split Channels。執行Image > Rename..重新命名成 red, green, blue 三張獨立的灰階影像。
  2. 分割細胞核:
    • 選取 (blue) 這張影像。
    • 執行 Image > Adjust > Threshold... 來選取細胞核。
    • 點擊 Apply 將其轉換為二值化影像。
  3. 將細胞核 ROI 加入manager:
    • 執行 Analyze > Analyze Particles...
    • 設定 Size 來過濾掉小雜訊,例如 50-Infinity
    • 勾選 Add to Manager,然後點擊 OK,所有細胞核的輪廓都被加入到 ROI manager中了。
    • 在 ROI manager 刪掉不屬於細胞核的部份,例如部份文字可能被選入 ROI。

2. 定義細胞區域

選取 (red) 通道影像,因為能大致顯示整個細胞的輪廓。

  1. 定義細胞粗略範圍
    • 選擇紅色通道影像,執行Image > Duplicate..,複製一張,接下來的操作都用這張圖來運算。
    • 使用工具列的圓形圈選工具,右鍵選擇Selection Brush Tool,這可以讓你用筆刷的方式圈出細胞界線。針對左上角的單一細胞,用此工具粗略畫出細胞範圍。
    • 執行Edit › Selection › Make Inverse,這會變成選取細胞之外的部份。再執行Edit > Clear,這可以讓細胞之外的區域都清除。再執行一次Edit › Selection › Make Inverse,又可以選回原來的細胞範圍。
  2. 定義細胞精確範圍
    • 執行Image > Adjust > Threshold..選擇出細胞的精細範圍,中間有洞沒關係。按下apply,此影像會轉成遮罩影像。
    • 針對此遮罩影像,執行Process › Binary › Fill Holes,可以將細胞之間的界線填滿,這樣就產生一個細胞精細輪廓的二值化遮罩影像。
    • 針對此遮罩影像,執行Edit › Selection › Create Selection,可以將其轉為選區,在 ROI Manager按下Add,就可以有單獨一個細胞的ROI。可以點擊 Rename... 將其命名為 Cell-1

3. 定義細胞質區域

  1. 在ROI Manager找尋屬於前述細胞的細胞核區域,將之rename為Nu-1
  2. ctrl同時選中Cell-1Nu-1,選擇點擊 More >> 按鈕,選擇 XOR。(XOR是互斥,請理解成「有你就沒有我,有我就沒有你」)
  3. 這會產生一個新的 ROI,其形狀就像一個甜甜圈,這就是我們需要的細胞質區域
  4. 將這個新的 "甜甜圈" ROI 也加入manager,並命名為 Cyto-1
  5. 你可以選中Cyto-1之後,執行Edit › Selection › Create Mask,就可以看見這個甜甜圈形狀的細胞質。

現在,我們的 ROI manager中應該至少有三個 ROI:Nu-1Cell-1Cyto-1

進行定量分析

你可以針對單一影像的多個ROI進行測量,也可以針對一個stack的每個slice,作多個ROI的測量。

  1. 單一影像,多個ROI的測量

    • 同時選取你要測量的ROI,並選擇要測量的影像,按下ROI manager的Measure
  2. 單一stack,多個ROI的測量

    • 你可以再開啟原始的Fluorescent Cells.tif,或是將已經經過背景扣除的三張影像再透過Image > Color > Merge Channels或是Imagew > Stacks > Images to Stack組合成stack。
    • 在 ROI manager視窗中,選中多個ROI,點擊 More >> 按鈕,然後選擇 Multi Measure

共定位分析

在完成細胞核、細胞質、細胞區域的 ROI 定義後,我們可以直接進行螢光通道的共定位分析。以下以 ImageJ 內建的 Coloc2 工具為例,說明操作流程與指標解讀。

操作步驟

  1. 準備影像與 ROI

    • 前述步驟已將紅色(F-Actin)與綠色(Tubulin)通道分離,並建立細胞、細胞核、細胞質的 ROI。
    • 確認 ROI Manager 中已包含欲分析的區域(如 Cyto-1、Nu-1、Cell-1)。
  2. 啟動 Coloc2 分析

    • 執行 Analyze > Colocalization Analysis > Coloc 2
    • 在 Coloc2 視窗中,分別選擇紅色與綠色通道影像作為 Channel 1 和 Channel 2。
    • 在 Mask/ROI 欄位選擇欲分析的 ROI(例如 Cyto-1)。
    • 設定分析參數(如 Pearson、Manders、Costes、Li 等),可依需求勾選。
  3. 執行與結果解讀

    • 點擊「OK」開始分析。
    • 結果視窗會顯示各項共定位指標數值與相關圖像(散點圖、遮罩、回歸線等)。
    • 數值結果會顯示於 ImageJ Log 視窗,可複製匯入統計軟體或試算表。

主要指標簡介

  • Pearson 相關係數:衡量兩通道像素強度的線性相關性,範圍 -1 ~ +1。+1 表示完全正相關,0 無相關,-1 完全反相關。
  • Manders 分割係數:分別計算兩通道中共定位像素的螢光量佔總螢光量的比例,範圍 0 ~ 1。越接近 1 表示共定位程度越高。
  • Costes 統計檢定:評估觀察到的相關性是否顯著高於隨機重疊,P 值 < 0.05 表示共定位具統計意義。
  • Li's ICQ:衡量像素強度對的共現性,+0.5 完美共定位,0 隨機分佈,-0.5 空間排斥。

imagej課程:案例分析-多目標測量:Roi manager與形態學分析

多目標測量:ROI manager與形態學分析

在許多生物影像中,我們需要一次測量多個物件(例如細胞、胚胎)。手動一個個圈選不僅耗時,也容易出錯。本章節將以 embryos.jpg 範例影像為例,進行標準的自動化分析流程:從影像分割、形態學處理,到使用 ROI Manager 進行批次測量。

1. 準備工作:開啟影像、校正與設定

在進行任何測量之前,首要步驟是確保影像設定正確,讓後續的數據具有科學意義。

  1. 開啟範例影像: File > Open Samples > Embryos.jpg
  2. 設定比例尺: 為了讓測量結果具有物理意義(如 µm²),而不是像素(pixels),必須進行空間校正。請使用直線工具量測後,執行 Analyze > Set Scale... 來設定。。
  3. 設定測量項目:
    • 執行 Analyze > Set Measurements...
    • 在對話框中,勾選感興趣的測量項目,例如:AreaMean gray valuePerimeterFit EllipseShape descriptors
    • 點擊 OK。此設定將會應用於後續所有的測量指令。

2. 自動化分析流程

此流程適用於快速、大量地處理特徵較為一致的物件。

步驟 2.1: 影像分割

我們的目標是產生一張黑白分明的二值化遮罩 (Binary Mask),其中白色代表胚胎,黑色代表背景。

  1. 轉換為灰階: 這是一張彩色影像,但分割通常在單一灰階通道上進行。執行 Image > Type > 8-bit
  2. 閾值分割 (Thresholding): 執行 Image > Adjust > Threshold... (快捷鍵 Ctrl+Shift+T)。ImageJ 會自動選擇一個閾值,觀察影像,大部分胚胎應該被標示為紅色。點擊 Apply,將影像轉換為黑白的二值化影像。

此時我們的分割結果可能不完美,這可以用形態學處理解決。

步驟 2.2: 形態學處理 (清理與分離物件)

目標是得到一張乾淨、且每個胚胎都獨立分開的二值化遮罩。

步驟 2.3: 自動選取並傳送至 ROI manager

現在,我們使用 Analyze Particles 功能來自動偵測所有胚胎,並將它們的輪廓統一交給 ROI manager

  1. 執行粒子分析:
    • 執行 Analyze > Analyze Particles...
    • 在對話框中進行以下關鍵設定:
      • Size (pixel^2): 設定一個合理的範圍,例如 500-Infinity,以過濾掉分割後可能殘留的微小雜訊點。
      • Show: 選擇 Outlines。這會產生一張新的影像,顯示所有被偵測到的物體輪廓。
      • 勾選 Display results:顯示測量結果表格。
      • 勾選 Add to Manager:此選項會將每一個被偵測到的物體輪廓作為一個獨立的 ROI,自動加入到 ROI manager中。
    • 點擊 OK

3. 手動選取流程

雖然自動化流程很強大,但有時你需要測量的目標不規則、自動分割效果不佳,或只想分析其中幾個特定物件。在這種情況下,手動選取結合ROI manager是更精確、更靈活的方法。

  1. 開啟 ROI manager: 如果尚未開啟,請執行 Analyze > Tools > ROI Manager...
  2. 手動圈選: 在主工具列選擇一個選取工具,例如 手繪選取工具 (Freehand Selection)
  3. 仔細地沿著第一個胚胎的邊緣畫出輪廓。
  4. 加入manager: 在 ROI manager視窗中,點擊 Add [t] 按鈕。第一個胚胎的選區 (ROI) 就被儲存起來了。
  5. 重複步驟 3 和 4,直到所有你想測量的胚胎都已圈選並加入到 ROI manager中。

4. 使用 ROI manager進行批次測量與分析

無論是透過自動還是手動流程,最終我們都得到了一個包含多個選區的 ROI manager。

步驟 4.1: 批次測量

在 ROI manager視窗中,點擊 Measure 按鈕。ImageJ 會對清單中的每一個 ROI 進行測量,並將結果逐行顯示在 "Results" 表格中。

步驟 4.2: 數據分析與匯出

  1. 計算基本統計:
    • 在 "Results" 表格的選單中,選擇 Results > Summarize
    • 一個新的 "Summary" 視窗會彈出,自動計算出每一欄數據的平均值 (Mean)、標準差 (Standard Deviation) 等統計資訊。
  2. 繪製分佈圖:
    • 在 "Results" 表格中,點擊你想分析的欄位標題(例如 Area),使其反白。
    • 執行 Results > Distribution...,ImageJ 會產生該欄數據的直方圖,讓你直觀地看到分佈情況。
  3. 導出數據進行進階分析:
    • 在 "Results" 表格中,選擇 File > Save As...
    • 將檔案儲存為 .csv 格式。這個檔案可以輕易地被 Excel、Google Sheets 或其他統計軟體開啟,以進行更深入的分析與圖表繪製。

步驟 4.3: ROI 管理與視覺化

ROI manager的其他功能:

  • 視覺化與標示:
    • 勾選 Show All,所有胚胎的輪廓會被顯示在原始影像上。
    • 接著點擊 Labels,每個 ROI 的編號會被標示在影像上,你可以對應影像上的胚胎與 "Results" 表格中的數據。
  • 個體操作與儲存:
    • 在清單中點選任一 ROI,它會在影像上高亮顯示。
    • 你也可以使用 Delete 刪除特定的 ROI,或用 Rename 重新命名。
    • 點擊 Save... 可以將這一整組 ROI 儲存成一個 .zip 檔案,方便未來重新載入 (Open...) 進行分析,無需重複前面的分割步驟。

imagej課程:影像紋理分析

影像紋理分析 (Image Texture Analysis)

除了強度和形狀,紋理 (Texture) 描述了像素鄰域內的空間強度變化模式,如粗糙、平滑、規律等。

本單元介紹紋理分析的基本概念,並以灰階共生矩陣 (Gray-Level Co-occurrence Matrix, GLCM) 為例,用 ImageJ/Fiji 實作 MRI 腦組織分析案例,分析灰白質的紋理特徵。


什麼是影像紋理?

影像紋理是指影像中像素灰階分佈的局部變化模式。它不是描述單一像素,而是描述像素與其周圍鄰居的空間關係。這些模式可以被量化為特徵,例如:

  • 粗糙 vs. 平滑 (Rough vs. Smooth)
  • 規律 vs. 隨機 (Regular vs. Random)

紋理特徵能夠補充形狀與強度資訊,是生醫影像分析中量化影像細微變化的重要工具。


紋理分析的理論基礎

紋理分析的核心是量化影像中像素間的「灰階關係」,通常從以下角度描述:

  • 灰階差異大小(對比度)
  • 紋理的規律程度(均勻性)
  • 資訊豐富程度(熵)
  • 能量分佈(能量或二階矩)

紋理分析的應用

紋理分析在醫學影像中應用廣泛,能輔助電腦進行診斷與分類:

  • 腫瘤診斷: 利用紋理特徵判斷腫瘤的良惡性(例如 MRI、超音波影像)。惡性腫瘤的紋理通常更不均勻、更複雜。
  • 組織分類: 區分不同類型的生物組織(如肌肉、脂肪、纖維組織)。
  • 疾病預測與分期: 透過紋理變化預測疾病進程(如肝臟纖維化程度)。
  • 醫學影像輔助診斷 (CAD): 作為機器學習、深度學習模型的重要特徵來源。

GLCM(灰階共生矩陣)

GLCM 是什麼?

GLCM互動範例
灰階共生矩陣 (Gray-Level Co-occurrence Matrix, GLCM) 是最經典的紋理分析統計方法。它透過一個矩陣來描述影像中像素的空間關係。這個矩陣記錄了在特定方向 (Angle)距離 (Distance) 下,成對像素的灰階值共同出現的頻率。

舉例來說,當設定 方向=0°距離=1 時,GLCM 統計的就是影像中每個像素與其正右方相鄰像素的灰階值組合出現了幾次。

GLCM 計算範例

假設有一張 \(3 \times 3\) 的灰階影像如下:

100 100 101
100 101 102
101 102 102

這裡的灰階值只有:100、101、102。

1. 設定計算條件

  • 方向:0°(向右)
  • 距離:1 像素

只考慮每個像素與右邊像素的組合關係。

2. 找出像素對

從影像中列出右側鄰居的像素對:

  • (100, 100)
  • (100, 101)
  • (100, 101)
  • (101, 102)
  • (101, 102)

3. 建立 GLCM

列出灰階對應次數:

i\j 100 101 102
100 1 2 0
101 0 0 2
102 0 0 0

4. 正規化 GLCM

將所有出現次數除以總像素對數(5 對):

i\j 100 101 102
100 0.2 0.4 0
101 0 0 0.4
102 0 0 0

5. 計算特徵量

(1) Contrast(對比度)

\[ Contrast = \sum_{i,j} (i-j)^2 \times P(i,j) \]

計算各元素:

  • (100,100): \((100-100)^2 \times 0.2 = 0\)
  • (100,101): \((100-101)^2 \times 0.4 = 1 \times 0.4 = 0.4\)
  • (101,102): \((101-102)^2 \times 0.4 = 1 \times 0.4 = 0.4\)

加總:

\[ Contrast = 0 + 0.4 + 0.4 = 0.8 \]

(2) Homogeneity(均勻性)

\[ Homogeneity = \sum_{i,j} \frac{P(i,j)}{1 + |i-j|} \]

計算各元素:

  • (100,100): \(\frac{0.2}{1+0} = 0.2\)
  • (100,101): \(\frac{0.4}{1+1} = 0.2\)
  • (101,102): \(\frac{0.4}{1+1} = 0.2\)

加總:

\[ Homogeneity = 0.2 + 0.2 + 0.2 = 0.6 \]

(3) Entropy(熵)

\[ Entropy = -\sum_{i,j} P(i,j) \log_2(P(i,j)) \]

計算各元素(取對數基底 2):

  • (100,100): \(-0.2 \times \log_2(0.2) \approx 0.464\)
  • (100,101): \(-0.4 \times \log_2(0.4) \approx 0.528\)
  • (101,102): \(-0.4 \times \log_2(0.4) \approx 0.528\)

加總:

\[ Entropy \approx 0.464 + 0.528 + 0.528 = 1.52 \]

小結

這張小影像的 GLCM 特徵是:

特徵 數值
Contrast 0.8
Homogeneity 0.6
Entropy 1.52

使用imagej

分析案例:量化灰質與白質的結構特徵

  • 背景知識:
  • 灰質 (Gray Matter): 主要由神經元胞體、樹突等組成。其結構相對異質、複雜
  • 白質 (White Matter): 主要由密集、平行排列的髓鞘化神經纖維束構成。其結構相對均質、有序
  • 分析假設:
  • 灰質的紋理應該更粗糙 (低均質性, 高對比度)。
  • 白質的紋理應該更平滑 (高均質性, 低對比度)。

操作步驟

準備工作

  1. 開啟影像: 開啟範例影像 File > Open Samples > T1 Head (2.4M, 16-bits)
  2. 開啟 ROI 管理器: 執行 Analyze > Tools > ROI Manager...
  3. 開啟Macro 在Text Window貼上以下Macro
macro "Main" {

    step = 1;

    calculateASM = true;
    calculateContrast = true;
    calculateCorrelation = true;
    calculateIDM = true;
    calculateEntropy = true;

    run("Clear Results");

    n = roiManager("count");
    if (n == 0) exit("ROI Manager 中沒有 ROI");

    for (i = 0; i < n; i++) {
        roiManager("select", i);
        GLCM_Texture_Macro(i, step, calculateASM, calculateContrast, calculateCorrelation, calculateIDM, calculateEntropy);
    }

    print("GLCM Texture analysis done for " + n + " ROIs.");
}

function GLCM_Texture_Macro(roiIndex, step, doASM, doContrast, doCorrelation, doIDM, doEntropy) {


    if (bitDepth() != 8) {
        exit("僅支援8-bit灰階影像");
    }

    getSelectionBounds(x, y, w, h);

    pixels = newArray(w * h);
    idx = 0;
    for (yy = y; yy < y + h; yy++) {
        for (xx = x; xx < x + w; xx++) {
            pixels[idx] = getPixel(xx, yy);
            idx++;
        }
    }

    size = 257;
    glcm = newArray(size * size);
    Array.fill(glcm, 0);

    pixelCounter = 0;

    // 0度方向 GLCM
    for (row = 0; row < h; row++) {
        for (col = 0; col < w - step; col++) {
            a = pixels[row * w + col];
            b = pixels[row * w + col + step];
            index1 = a * size + b;
            index2 = b * size + a;
            glcm[index1] += 1;
            glcm[index2] += 1;
            pixelCounter += 2;
        }
    }

    for (i = 0; i < size * size; i++) {
        glcm[i] /= pixelCounter;
    }

    asm = 0;
    contrast = 0;
    correlation = 0;
    IDM = 0;
    entropy = 0;

    px = 0;
    py = 0;

    for (a = 0; a < size; a++) {
        for (b = 0; b < size; b++) {
            val = glcm[a * size + b];
            px += a * val;
            py += b * val;
        }
    }

    stdevx = 0;
    stdevy = 0;

    for (a = 0; a < size; a++) {
        for (b = 0; b < size; b++) {
            val = glcm[a * size + b];
            stdevx += (a - px) * (a - px) * val;
            stdevy += (b - py) * (b - py) * val;
        }
    }

    for (a = 0; a < size; a++) {
        for (b = 0; b < size; b++) {
            val = glcm[a * size + b];
            asm += val * val;
            contrast += (a - b) * (a - b) * val;
            if (stdevx != 0 && stdevy != 0) {
                correlation += ((a - px) * (b - py) * val) / (stdevx * stdevy);
            }
            IDM += val / (1 + (a - b) * (a - b));
            if (val > 0) {
                entropy -= val * log(val);
            }
        }
    }

    nRows = nResults();
    setResult("ROI Index", nRows, roiIndex + 1);
    setResult("Step size", nRows, step);
    setResult("ROI Name", nRows, Roi.getName);
    setResult("Angular Second Moment", nRows, asm);
    setResult("Contrast", nRows, contrast);
    setResult("Correlation", nRows, correlation);
    setResult("Inverse Difference Moment", nRows, IDM);
    setResult("Entropy", nRows, entropy);
    updateResults();

    print("ROI " + (roiIndex + 1) + " GLCM features:");
    print("  ASM = " + asm);
    print("  Contrast = " + contrast);
    print("  Correlation = " + correlation);
    print("  IDM = " + IDM);
    print("  Entropy = " + entropy);
}


選取ROI Selection

我們需要在典型的灰質和白質區域手動定義幾個 ROI 以進行比較。

  1. 瀏覽影像堆疊,找到一個腦部結構清晰的切片,然後做Image › Duplicate...,複製其中一張影像。
  2. GLCM 的計算需要灰階影像,將影像轉換為 8 位灰階影像:Image > Type > 8-bit
  3. 從 ImageJ 主工具列選擇 自由選取工具 (freehand Selection)
  4. 定義灰質 ROI:
    • 在一個大片的、均勻的灰質區域內,畫一個大小適中的橢圓。
    • 在 ROI manager中點擊 Add [t],然後點擊 Rename... 將其命名為 grey
  5. 定義白質 ROI:
    • 先在ROI manager選擇 grey的ROI,然後按鍵盤的方向鍵,將這個區域移動到白質區域。
    • 加入 ROI 管理器並命名為 white
  6. 執行Macro的GLCM 分析,就會分析ROI manager的每一個ROI,並寫入Result。

結果解讀與結論

觀察表格,這些數據是否符合我們對灰白質的主觀感受?白質的紋理確實比灰質更平滑、更均質,而灰質的紋理則更粗糙、更複雜。

特徵名 英文 意義 解讀
角秒矩 Angular Second Moment (ASM) 衡量紋理的均勻性或一致性 值越高表示紋理越規則、均勻。
對比度 Contrast 鄰近像素間灰階差異的加權總和,反映影像紋理的「粗糙程度」 高對比=紋理粗糙
相關性 Correlation 衡量像素間灰階的線性相關性 值高表示像素間關係有序、噪音少。
反差異矩 Inverse Difference Moment (IDM) / Homogeneity 鄰近像素灰階越接近得分越高 值高表示像素強度相似,紋理平滑。
Entropy 量化灰階分佈的隨機性,GLCM元素的平方和 數值高表示紋理複雜、無序。

imagej課程:特徵擷取

特徵擷取

  • Analyze > Analyze Particles...
  • 在二值影像上偵測獨立的物件 (粒子/細胞)。
  • 可設定大小 (Size) 和圓形度 (Circularity) 範圍來篩選目標。
  • 測量參數包括:面積 (Area)、中心點 (Centroid)、周長 (Perimeter)、圓形度、長短軸等。
  • 勾選 Display results, Clear results, Summarize, Add to Manager 等選項控制輸出。

認識測量參數 (Set Measurements)

在執行 Analyze > MeasureAnalyze Particles... 之前,我們可以透過 Analyze > Set Measurements... 指令來決定結果表格中要顯示哪些測量項目。了解這些參數的意義,能幫助你選擇最適合研究目的的量化指標。

以下是常用參數的說明:

基本與強度測量

參數 (選項) 結果欄位 說明
Area Area 選區的面積。如果影像經過空間校正,單位會是物理單位(如 cm²),否則為像素平方 (pixels²)。
Mean Gray Value Mean 選區內所有像素的平均灰階值。若經過強度校正,則單位為校正後的物理單位。對於RGB影像,會先轉換為灰階再計算。
Standard Deviation StdDev 選區內像素灰階值的標準差,反映了亮度的離散程度。
Min & Max Gray Level Min, Max 選區內的最小與最大灰階值。
Modal Gray Value Mode 選區內出現頻率最高的灰階值(眾數),對應直方圖的最高峰。
Median Median 選區內像素灰階值的中位數。相較於平均值,較不受極端值(雜訊點)影響。
Integrated Density IntDen, RawIntDen 積分密度IntDen = Area × MeanRawIntDen = 選區內所有像素的灰階值總和。在螢光定量等分析中非常重要,能反映選區內訊號的總量。
Skewness Skew 偏度。衡量灰階分佈的不對稱性。正偏態表示分佈偏向左側(低亮度),負偏態表示偏向右側(高亮度)。
Kurtosis Kurt 峰度。衡量灰階分佈的峰態陡峭程度。高聳的峰態有較高的峰度值。

形狀與位置測量

參數 (選項) 結果欄位 說明
Perimeter Perimeter 選區的邊界長度(周長)。
Centroid X, Y 形心(幾何中心)。選區所有像素點X、Y座標的算術平均值,代表物體的幾何中心位置。
Center of Mass XM, YM 質心。以像素亮度為權重的座標平均值。質心會偏向選區中較亮的區域。
Bounding Rectangle BX, BY, Width, Height 邊界矩形。能完全包圍選區的最小矩形。回傳其左上角座標(BX, BY)及寬高。
Feret's Diameter Feret, FeretAngle, MinFeret 費雷特直徑(最大口徑)。選區邊界上任意兩點間的最長距離。MinFeret 則是最小口徑。常用來描述不規則物體的尺寸。
Fit Ellipse Major, Minor, Angle 擬合橢圓。計算出最能貼合選區的橢圓,並回傳其長軸(Major)、短軸(Minor)及長軸與X軸的夾角(Angle)。
Shape Descriptors Circ., AR, Round, Solidity 形狀描述子,一組用來量化形狀的指標:
- Circ. (圓形度): 4π*面積/周長²。值為1.0表示完美的圓形,越接近0.0表示越狹長。
- AR (長寬比): 長軸/短軸,需同時啟用 "Fit Ellipse"。
- Round (圓度): 4*面積/(π*長軸²),是長寬比的倒數。
- Solidity (實心度): 面積/凸包面積。值接近1表示物體較實心、無凹陷。

其他設定

參數 (選項) 說明
Area Fraction 顯示被閾值(Threshold)標紅的像素所佔的面積百分比。
Limit to Threshold 勾選後,所有測量(如Mean, Min, Max)都只會計算被閾值標紅的像素,忽略選區內未被標紅的像素。這對於在不完美的分割區域中精確測量訊號非常有用。
Stack Position 在處理影像堆疊(Stack)時,記錄測量發生在哪個通道(Ch)、切片(Slice)或幀(Frame)。
Display Label 在結果表格的第一欄顯示影像名稱和切片編號,方便辨識數據來源。
Redirect To 重定向。允許你在影像A上圈選ROI,但實際測量影像B上對應位置的像素值。對於多通道分析(如在DAPI通道上圈核,測量GFP通道的強度)極為重要。
Decimal Places 設定結果表格中小數點後顯示的位數。

輸出數據

  • 分析結果顯示在 ImageJ 的 Results Table 中。
  • 可將表格 File > Save As... 匯出成 .csv.txt 文件,以便後續使用 Excel, Python (Pandas), R 等工具進行統計分析和繪圖。

Show選項說明

請執行這個macro,觀察不同show產生的效果。

// 建立原始影像


newImage("original", "8-bit black", 512, 512, 1);
setColor(255);

// 畫圓形
makeOval(50, 50, 100, 100);
run("Fill");
run("Select None");

// 畫方形
makeRectangle(200, 50, 100, 100);
run("Fill");
run("Select None");

// 畫三角形(使用多邊形)
makePolygon(150,300, 250,300, 200,200);
run("Fill");
run("Select None");

// Binarize(轉為二值圖)
setThreshold(1, 255);
run("Convert to Mask");


// 各種 show 模式與對應標籤
shows = newArray(
    "Overlay",
    "[Overlay Masks]",
    "Outlines",
    "[Bare Outlines]",
    "Ellipses",
    "Masks",
    "[Count Masks]"
);

// 執行每種 show 模式
for (i = 0; i < shows.length ; i++) {
    selectImage("original");
    showOption = shows[i];

    if (i == 0 || i == 1) run("Duplicate...", "title="+ showOption);

    run("Analyze Particles...", " show=" + showOption );
    wait(200); // 等待新視窗建立
    idList = getList("image.titles");
    newest = idList[lengthOf(idList) - 1]; // 最新產生的圖    
    selectImage(newest);
    rename(showOption);

}


imagej課程:用FFT處理週期性雜訊,與FFT其他應用

本範例展示如何在影像中加入週期性雜訊(條紋或點狀 pattern),並利用 ImageJ 觀察其傅立葉轉換(FFT)結果。


FFT 結果觀察

  • 條紋雜訊(stripe)
    頻譜圖會出現一對明顯的亮點,位置與條紋方向、頻率有關。
  • 點狀 pattern
    頻譜圖會出現多個亮點,形成規則的格點分布。
  • 調整 angle 參數,可觀察頻譜亮點的旋轉變化。
  • 調整 freqX 參數,可觀察頻譜亮點的位置變化。

實作範例

// 在影像上增加週期性雜訊:可切換「條紋」或「點狀 pattern」
// 觀察轉出的FFT


// ==== 參數 ====
mode = "stripe"; // "stripe" = 條紋, "pattern" = 點狀
// 條紋時只用 freqX
freqX = 10;       // X方向週期
freqY = 20;       // Y方向週期
amp   = 60;       // 雜訊強度 (0~255)
angle = 30;       // 旋轉角度 (度數)

// ==== 測試影像 ====
run("Clown");
run("8-bit");
rename("Noisy");

width = getWidth();
height = getHeight();
theta = angle * PI / 180;

setBatchMode(true);

for (y=0; y<height; y++) {
    for (x=0; x<width; x++) {

        // 旋轉座標
        xp =  x * cos(theta) + y * sin(theta);
        yp = -x * sin(theta) + y * cos(theta);

        if (mode == "stripe") {
            // 條紋
            value = amp * sin(2 * PI * xp / freqX);
        } else {
            // 點狀 pattern
            value = amp * sin(2 * PI * xp / freqX) * sin(2 * PI * yp / freqY);
        }

        // 只增亮
        //if (value < 0) value = 0;

        v = getPixel(x, y) + value;

        if (v > 255) v = 255;
        if (v < 0) v = 0;
        setPixel(x, y, v);
    }
}

setBatchMode(false);
resetMinAndMax();
run("FFT");

在 FFT 頻譜上處理並反轉回空間域

你可以在 FFT 頻譜圖上進行處理(如遮罩、消除亮點),再做 Inverse FFT(Process › FFT › Inverse FFT)觀察效果。

流程

  1. 產生含週期性雜訊的影像並做 FFT(同前述腳本)。
  2. 手動或自動在 FFT 頻譜圖上遮罩亮點(消除雜訊頻率)。
  3. 執行 Inverse FFT,觀察雜訊是否被移除。

補充說明

  • 你可以手動用橢圓工具在 FFT 頻譜圖上選取亮點,然後執行 Edit > ClearClear Outside
  • 遮罩掉亮點後再做 Process > FFT > Inverse FFT,即可看到雜訊被抑制的效果。

原理解釋

在頻域中,週期性雜訊會對應到特定的頻率成分。透過傅立葉轉換,我們可以將影像從空間域轉換到頻域,並觀察到這些雜訊成分的頻譜特徵。當我們在頻譜圖上進行遮罩處理,實際上是去除了這些特定頻率的影響,進而達到去雜訊的效果。


自訂濾波器

從 FFT 頻譜圖上,你也可以使用自訂濾波器來處理影像。這可以讓你更精確地控制哪些頻率成分被保留或去除。
執行 Process › FFT › Custom Filter...


FFT 自相關

透過自相關分析,我們可以進一步了解影像中的週期性雜訊特徵。自相關函數可以幫助我們識別影像中重複出現的模式,並為去雜訊提供依據。

  1. 使用一個有週期性條紋的圖,或是洋蔥細胞顯微圖做 FFT,再使用 Process › FFT › FD Math...,使用同一張圖做自相關運算 correlate,勾選 Do inverse transform
  2. 觀察自相關結果,會顯示出影像中週期性條紋的特徵。

imagej課程:形態學重建去噪


形態學重建是基於形態學操作(膨脹、腐蝕),但能更精確地保留物件的原始形狀。其核心思想是使用一張「標記影像 (Marker Image)」在另一張「遮罩影像 (Mask Image)」的約束下,進行迭代式的膨脹或腐蝕,直到影像不再變化為止。

基本原理

可以將灰階影像想像成一個三維的地形圖,像素的灰階值代表該點的高度。

  • 遮罩影像 (Mask Image): 通常是我們的原始影像。它定義了重建過程的「地形邊界」,也就是像素值所能達到的上限(或下限)。
  • 標記影像 (Marker Image): 通常是原始影像經過簡單形態學處理(如腐蝕或膨脹)後的結果。它作為重建過程的「起始點」或「種子」。

形態學重建有兩種基本操作:

  1. 膨脹式重建 (Reconstruction by Dilation):

    • 過程: 從「標記影像」開始,反覆進行膨脹操作。
    • 約束: 每一次膨脹的結果,其像素值都不能超過「遮罩影像」對應位置的像素值。
    • 比喻: 想像從標記影像的「山峰」開始注水,水會向周圍流動(膨脹),但水面高度永遠不能超過遮罩影像(原始地形)的高度。最終,所有能從標記點到達的區域都會被「淹沒」到與原始地形相同的高度。
  2. 腐蝕式重建 (Reconstruction by Erosion):

    • 過程: 從「標記影像」開始,反覆進行腐蝕操作。
    • 約束: 每一次腐蝕的結果,其像素值都不能低於「遮罩影像」對應位置的像素值。
    • 比喻: 想像將遮罩影像(原始地形)倒過來,然後從標記影像的位置開始向上「填充」,但填充物不能超出原始地形的邊界。

應用:優於傳統開/閉運算的濾波

形態學重建最常見的應用是「重建式開運算」和「重建式閉運算」,用途是影像去噪,將亮點和暗點移除。

1. 重建式開運算 (Opening by Reconstruction) - 去除亮點

此操作能移除影像中的小型亮點(地形圖中的「小山峰」),同時完美保留較大物件的形狀和尺寸。

  • 步驟:
    1. 腐蝕 (Erosion): 對原始影像(遮罩)進行腐蝕,得到標記影像。這個步驟會壓平或移除所有小於結構元素的亮點(山峰)。
    2. 膨脹式重建 (Reconstruction by Dilation): 使用腐蝕後的標記影像,在原始影像的約束下進行膨脹式重建。
  • 結果: 原始影像中的主要結構會被完整「重建」回來,但那些在第一步被移除的小山峰則無法恢復,從而達到了去除亮點的效果。

2. 重建式閉運算 (Closing by Reconstruction) - 填補暗點

此操作能填補影像中的小型暗點或孔洞(地形圖中的「小坑洞」),同時保留物件的形狀。

  • 步驟:
    1. 膨脹 (Dilation): 對原始影像(遮罩)進行膨脹,得到標記影像。這個步驟會填滿所有小於結構元素的暗點(坑洞)。
    2. 腐蝕式重建 (Reconstruction by Erosion): 使用膨脹後的標記影像,在原始影像的約束下進行腐蝕式重建。
  • 結果: 原始影像中的主要結構會被「重建」回來,但那些在第一步被填平的小坑洞則無法恢復,從而達到了填補暗點的效果。

與中值濾波器 (Median Filter) 的比較

雖然形態學重建和中值濾波器(Median Filter)都可以用於影像去噪,但原理和適用情境有顯著差異:

特性 (Feature) 形態學重建 (Morphological Reconstruction) 中值濾波器 (Median Filter)
基本原理 使用標記影像在遮罩影像的約束下進行迭代式膨脹/腐蝕。 將每個像素替換為其鄰域內像素灰階值的中位數。
形狀保留 極佳。能完美保留大於結構元素的物件輪廓與尺寸,不會造成收縮或變形。 良好,但較大半徑的濾波可能導致物件的尖角被鈍化、邊緣輕微變形。
去噪機制 移除尺寸小於結構元素的亮點(重建式開)或暗點(重建式閉)。 有效移除椒鹽式雜訊(Salt-and-pepper noise)等孤立的極端值像素。
適用情境 需要在不影響主要物件形狀的前提下,精確移除特定尺寸的雜訊或小物件。 快速去除隨機的亮暗點雜訊,且對邊緣的模糊效應比均值濾波小。
缺點 計算量較大,過程較複雜。 對於大片叢集的雜訊效果有限,且可能模糊細微的紋理。

實作

以下 Macro 腳本將演示如何使用形態學重建來移除 Dot Blot 範例影像中的亮點與暗點,並與中值濾波器 (Median Filter) 的結果進行比較。

run("Dot Blot");
run("Invert");
run("Duplicate...", "title=origin");

/* 
 * 去除亮點
 * 對原始灰階影像進行一次腐蝕(Erosion)。腐蝕會將所有小的山峰消除或變淺,形成一個平滑的底圖。這個平滑後的影像就是你的標記影像。
 */
selectImage("origin");
run("Morphological Filters", "operation=Erosion element=Square radius=2");
rename("erosion-marker");


/*
 * 執行膨脹式重建 (reconstructByDilation),將腐蝕後的標記影像在原始影像的約束下進行膨脹。這個過程會把標記影像「膨脹」回原始影像的形狀,但那些在腐蝕階段被移除的亮點將無法恢復。
 */
run("Morphological Reconstruction", "marker=erosion-marker mask=origin type=[By Dilation] connectivity=8");
rename("deLightResult");


/*
 * 移除暗點(Pepper Noise)
 * 暗點在灰階影像的地形圖中代表微小的「山谷」。膨脹式重建的「注水」原理正好可以用來填平這些小山谷。
 * 對原始灰階影像進行一次膨脹(Dilation)。膨脹會有效地小的「山峰」(包括亮點)擴大或與其他山峰合併,暗點填平,形成一個平滑的頂圖。這個平滑後的影像就是你的標記影像。
 */
selectImage("origin");
run("Morphological Filters", "operation=Dilation element=Square radius=2");
rename("dilation-marker");

/*
 * 執行腐蝕式重建 (reconstructByErosion),將膨脹後的標記影像在原始影像的約束下進行腐蝕。這個過程會把標記影像「腐蝕」回原始影像的形狀,但那些在膨脹階段被移除的亮點將無法恢復。
 */

run("Morphological Reconstruction", "marker=dilation-marker mask=origin type=[By Erosion] connectivity=8");
rename("deDarkResult");



/*
 * 結合以上兩者操作,進行連續操作
 * 
*/


selectImage("origin");
run("Morphological Filters", "operation=Erosion element=Square radius=2");
rename("erosion-marker");


run("Morphological Reconstruction", "marker=erosion-marker mask=origin type=[By Dilation] connectivity=8");
rename("deLightResult");


selectImage("deLightResult");
run("Morphological Filters", "operation=Dilation element=Square radius=2");
rename("dilation-marker");

run("Morphological Reconstruction", "marker=dilation-marker mask=deLightResult type=[By Erosion] connectivity=8");
rename("result");

// 新增中值濾波器做比較
selectImage("origin");
run("Duplicate...", "title=median-result");
run("Median...", "radius=2");


// 觀察原始影像和兩種處理後影像的差異
imageCalculator("Subtract create 32-bit", "origin","result");
selectImage("Result of origin");
rename("Diff-Reconstruction");
setMinAndMax(-100, 100);
run("3-3-2 RGB");

imageCalculator("Subtract create 32-bit", "origin","median-result");
selectImage("Result of origin");
rename("Diff-Median");
setMinAndMax(-100, 100);
run("3-3-2 RGB");

run("Tile");

imagej課程:分析血管

教學影片

分析需求

圖為血管內皮細胞在Matrigel內形成了微血管網絡,需要分析 

1. 血管環數量(中間有一個洞,周圍一圈,就可以稱做一個環)

 2. 微血管總長度 (微血管形成的網路所有length的總和)

 3. 微血管平均管徑

示範Macro

請參考教學影片,逐步執行Macro觀察

// 先開啟檔案
run("8-bit");
rename("origin");

// 裁切
makeRectangle(0, 0, 864, 668);
run("Crop");


// 降噪
selectImage("origin");
run("Duplicate...", "title=deNoise ");
run("Gaussian Blur...", "sigma=2");
run("Median...","radius=3");


// 局部對比度增強 CLAHE
selectImage("deNoise");
run("Duplicate...", "title=CLAHE ");
run("Enhance Local Contrast (CLAHE)", "blocksize=63 histogram=256 maximum=3 mask=*None*");

// MorphologicalSegmentaion
selectImage("deNoise");
run("Duplicate...", "title=deNoiseInverse");
run("Invert");
run("Morphological Segmentation");



// 局部threshold
selectImage("CLAHE");
run("Duplicate...", "title=localThreshold");
run("Auto Local Threshold", "method=Niblack radius=15 parameter_1=0 parameter_2=0 white");

// 形態學處理
selectImage("localThreshold");
run("Duplicate...", "title=fillHoles");
run("Fill Holes");


// 產生distance map
selectImage("fillHoles");
run("Duplicate...", "title=Distance");
run("Distance Map");

// 產生Maxima當種子
selectImage("Distance");
run("Find Maxima...", "prominence=10 exclude output=[Point Selection]");
roiManager("Add");


// 血管寬度與長度估算
selectImage("deNoise");
run("Duplicate...", "title=ridge ");
run("Ridge Detection", "line_width=10 high_contrast=150 low_contrast=20 darkline estimate_width extend_line displayresults add_to_manager method_for_overlap_resolution=SLOPE sigma=3.39 lower_threshold=0.51 upper_threshold=1.36 minimum_line_length=0 maximum=0");


/*
// 產生梯度圖
selectImage("deNoise");
run("Duplicate...", "title=edge");
run("Find Edges");
*/



/*
// 降噪更多產生distance map
selectImage("origin");
run("Duplicate...", "title=deNoiseMoreInvert ");
run("Gaussian Blur...", "sigma=2");
run("Median...","radius=2");
run("Auto Local Threshold", "method=Niblack radius=15 parameter_1=0 parameter_2=0 white");
run("Fill Holes");
run("Distance Map");
run("Invert");
run("Enhance Contrast", "saturated=0.35");
*/


imagej課程:偵測血管等長條形或管狀物體

管長計算

偵測管狀結構

Frangi Vesselness filter 是一種專門用來偵測影像中血管狀、管狀(tubular structures)結構的影像處理演算法,主要根據局部灰階變化的「二階導數資訊」來判斷結構是否像「管子」。

Hessian 矩陣

想像你用手在圖片表面摸,這個方法會幫你感受到圖片上哪裡是「凹進去」、「凸出來」或「平平的」。 Hessian 矩陣分析影像每個像素點的彎曲程度和方向,特別是找出線條、溝槽、彎曲的地方。

Frangi Vesselness filter 會觀察這些彎曲程度的數字(稱為「特徵值」(eigenvalue)),並依據這些數字來判斷某個區域像不像血管。

以2D圖片來說,管狀物的特徵是一個方向平、另一方向凹得很深,這種特徵就會在Frangi中被強調出來,分數越高越可能是血管

設定

  • spacing:代表影像每個 pixel 在各個維度上的實際物理間距,一般xy等距的影像設成1,1就可以。
  • scale:指的是 Frangi filter 中的σ 值,控制血管偵測的「粗細尺度」。

    • 每個 scale 會做一次偵測,最後將所有結果合併成為一個stack。
    • 通常填 1~4 個整數,代表從細到粗的血管寬度

後處理

執行Process › Filters › Frangi Vesselness之後,將stack做Image › Stacks › Z Project...,在此前後應該進行各種前處理,例如:

  • 區域化的對比調整
  • 遮罩設定

得到的成果再做骨架化處理,執行Plugins › Skeleton › Skeletonize (2D/3D)與分析骨架顯示結果,執行 Analyze › Skeleton › Analyze Skeleton (2D/3D),勾選Show detailed info

3D骨架化示範

  1. 開啟File › Open Samples › Bat Cochlea Volume蝙蝠耳蝸當成範例,這是一個已經二值化的影像。
  2. 執行Image › Stacks › 3D Project...或是 Plugins › 3D Viewer 觀察其立體結構。
  3. 對二值化影像輪廓進行骨架化處理,執行Plugins › Skeleton › Skeletonize (2D/3D)
  4. 分析骨架並顯示結果 Analyze › Skeleton › Analyze Skeleton (2D/3D),勾選Show detailed info

2D骨架化示範

  1. 執行以下macro,此範例會生成一個碎形樹,並產生程式預估的長度(繪製時就量測,可當作標準答案)。
  2. 針對範例圖片,先轉成8-bit影像。
  3. 對血管輪廓進行骨架化處理,執行Plugins › Skeleton › Skeletonize (2D/3D)
  4. 分析骨架並顯示結果 Analyze › Skeleton › Analyze Skeleton (2D/3D),勾選Show detailed info
  5. 將結果加總對照程式估計的長度。
// ==== 使用者可調參數 ====
totalTargetLength = 300;       // 目標總長度(像素)
maxDepth = 8;                  // 分支深度(越大分支越多)
angleVariation = 80;           // 分支角度變化範圍(度)
branchRatio = 0.7;             // 分支長度縮短比例

// ==== 隨機控制開關 ====
enableRandomness = false;       // 全域隨機控制開關
enableRandomAngle = false;      // 啟用隨機角度?
enableRandomLength = true;     // 啟用隨機長度?



// ==== 畫樹狀分支函數 ====
function drawBranch(x, y, angleDeg, length, depth) {
  if (depth == 0) return 0;

  if (totalDrawnLength + length > totalTargetLength)
    length = totalTargetLength - totalDrawnLength;
  if (length <= 0) return 0;

  angleRad = angleDeg * PI / 180;

  // 計算終點
  x2 = x + cos(angleRad) * length;
  y2 = y + sin(angleRad) * length;

  // 分支寬度隨深度調整
  maxRadius = 8;
  baseRadius = maxRadius * (depth / maxDepth);
  radius = baseRadius;
  if (enableRandomness && enableRandomLength)
    radius *= 0.8 + 0.4 * random();  // 半徑加入隨機變異
  if (radius < 1) radius = 1;

  // 繪製分支:使用小圓點堆疊形成粗線
  steps = floor(length);
  for (i = 0; i <= steps; i++) {
    px = x + cos(angleRad) * i ;
    py = y + sin(angleRad) * i ;
    makeOval(px - radius / 2, py - radius / 2, radius, radius);
    run("Fill");
  }

  totalDrawnLength += length;

  // 新分支長度與角度變化
  newLength = length * branchRatio;
  if (enableRandomness && enableRandomLength)
    newLength *= 0.8 + 0.4 * random();

  delta = angleVariation;
  if (enableRandomness && enableRandomAngle)
    delta *= (random() * 2 - 1);  // 在 ±angleVariation 範圍內隨機

  // 遞迴分支(左右)
  currentBranchLength = 0;
  if (!enableRandomness || random() < 0.8)
    currentBranchLength = currentBranchLength + drawBranch(x2, y2, angleDeg - delta, newLength, depth - 1);
  if (!enableRandomness || random() < 0.8)
    currentBranchLength = currentBranchLength + drawBranch(x2, y2, angleDeg + delta, newLength, depth - 1);

  return length + currentBranchLength;
}



// ==== 建立畫布 ====
width = 512;
height = 512;
newImage("Vessel Tree", "RGB black", width, height, 1);
setColor(255, 255, 255);
run("Line Width...", "line=3");

// ==== 全域變數 ====
totalDrawnLength = 0;

// ==== 主程式 ====
setBatchMode("hide");
setBatchMode(true); 

startX = width / 2;
startY = height - 10;
initialLength = totalTargetLength / 3.0;

print("開始繪製樹狀血管樹...");
totalDrawnLength = drawBranch(startX, startY, -90, initialLength, maxDepth);
setBatchMode(false); 
print("估計總長度(程式計算): " + totalDrawnLength);

//run("8-bit"); // 確保影像為8位元格式
//run("Skeletonize (2D/3D)"); // 對血管輪廓進行骨架化處理
//run("Analyze Skeleton (2D/3D)", "prune=none show display"); // 分析骨架並顯示結果,包括總長度



imagej課程:形態學運算

形態學運算(Morphological Operations)

形態學運算主要應用於二值影像,用來分析與處理影像中物件的形狀、結構與分布。相關功能集中於 Process > Binary > ...子選單中。

基本操作

  • Make Binary 建立二值圖: 將影像轉換成黑白(0/255)圖像。預設會根據選取區域或整張影像的直方圖,自動決定閾值。若已設定閾值(Image > Adjust > Threshold),將會跳出對話框詢問設定前景/背景顏色,以及是否反轉黑白。

  • Convert to Mask 轉為遮罩: 根據目前的閾值設定將影像轉成二值圖。若未設定閾值,則會自動計算。預設輸出為「反轉 LUT」(白為 0、黑為 255),除非在 Process > Binary > Options 中勾選了 Black Background

侵蝕與膨脹(Erode & Dilate)

  • Erode 侵蝕: 從黑色物件邊緣移除像素,相當於縮小物件。可用來去除尖角、毛刺或細小突出。對灰階影像可使用 Process > Filters > Minimum 模擬。

  • Dilate 膨脹: 向黑色物件邊緣加入像素,相當於擴大物件。可填補小孔或斷裂。對灰階影像可使用 Process > Filters > Maximum 模擬。

組合操作

  • Open 開啟: 先侵蝕再膨脹。可移除小雜訊、斷開細連線。適合清除背景雜點而不影響主體。

  • Close 關閉: 先膨脹再侵蝕。可填補小孔洞、連接相近物體。適合使主體更為連貫。

其他操作

  • Skeletonize 骨架化: 持續移除物體邊緣像素,直到只剩單像素寬的骨架。用於分析結構拓撲(如細胞通路)。

  • Outline 描邊: 對物件產生單像素寬邊框。可視為邊緣檢測的一種形式。

  • Distance Map 距離變換: 計算每個前景像素與最近背景像素的歐式距離,結果為灰階圖,產生Euclidian distance map (EDM)。適合用於分析粒子間距或後續分割。

  • Ultimate Points 終極點: 對距離圖找出每個粒子內最大內切圓的中心,灰階值代表半徑。可作為分割粒子依據。產生ultimate eroded points (UEPs)

  • Watershed 分水嶺分割: 自動分離接觸或重疊的粒子。流程包含建立距離圖、找終極點,然後從終極點開始膨脹直到互相接觸為止。適用於圓形、不重疊太多的粒子分離。

  • Voronoi 沃羅諾伊分割: 依據與最近兩個粒子的邊界距離,為每個粒子建立一個區域。適合做為粒子領域劃分(Voronoi tessellation)。

設定選項(Options)

透過 Process > Binary > Options... 可調整以下參數:

  • Iterations(次數): 設定侵蝕、膨脹、開啟、關閉等操作的重複次數。

  • Count(鄰近像素數): 決定侵蝕/膨脹時像素被加入/移除所需的鄰近像素數。

  • Black Background: 勾選此選項代表背景為黑,物件為白。這會影響大多數形態操作與距離圖的計算。

可用下列方式設定:

    // Plugin
    Prefs.blackBackground = true;

    // Macro
    setOption("black background", true);
  • Pad Edges when Eroding: 勾選時,侵蝕操作不會作用於影像邊緣(避免邊界損失)。

  • EDM Output(距離圖輸出格式): 設定 Distance Map、Ultimate Points、Voronoi 等輸出的格式:

    • "Overwrite":覆蓋原圖(8-bit)

    • "8-bit" / "16-bit" / "32-bit":輸出為新的影像,32-bit 為 subpixel 精度。

實作

幾何圖形

執行以下Macro,進行各種二值化操作,觀察圖形的變化


// 建立空白影像
newImage("BinaryDemo", "8-bit black", 512, 512, 1);
setForegroundColor(255, 255, 255);

// ---------- 粗圓 + 毛刺 ----------
for (i = 0; i < 3; i++) {
    x = 80 + i * 60;
    y = 80;
    r = 25;
    makeOval(x - r, y - r, r * 2, r * 2);
    fill();
}

// 毛刺圓形
centerX = 250;
centerY = 80;
nPoints = 36;
xPoints = newArray(nPoints);
yPoints = newArray(nPoints);
for (i = 0; i < nPoints; i++) {
    angle = 2 * PI * i / nPoints;
    r = 25 + random() * 10;
    xPoints[i] = centerX + r * cos(angle);
    yPoints[i] = centerY + r * sin(angle);
}
makeSelection("polygon", xPoints, yPoints); fill();

// ---------- 細線 ----------
for (i = 0; i < 4; i++) {
    y = 150 + i * 10;
    makeLine(50, y, 200, y);
    run("Draw", "slice");
}

// ---------- 貼邊形狀 ----------
makeRectangle(0, 300, 60, 60); fill();
makeRectangle(450, 300, 60, 60); fill();
makeRectangle(200, 450, 100, 60); fill();

// ---------- 破碎物件 ----------
setColor(255, 255, 255);
makeRectangle(300, 300, 20, 20); fill();
makeRectangle(321, 300, 20, 20); fill();
makeRectangle(342, 300, 20, 20); fill();
makeRectangle(321, 321, 20, 20); fill();

// ---------- 密集群圓 ----------
x0 = 400;
y0 = 400;
r = 15;
for (i = 0; i < 3; i++) {
    for (j = 0; j < 3; j++) {
        dx = x0 + i * 25;
        dy = y0 + j * 25;
        makeOval(dx - r, dy - r, r * 2, r * 2);
        fill();
    }
}

// 二值化
run("Make Binary");

細胞分佈

執行以下macro,產生三張圖片,模擬不同的粒子分佈,試試看執行Voronoi分隔。

// 參數設定
width = 512;
height = 512;
pointRadius = 3;

// 建立空白影像
newImage("Multi-Pattern Particles", "8-bit black", width, height, 1);
setForegroundColor(255, 255, 255);

// -------------------- 區域1:隨機分佈 --------------------
nRandom = 50;
for (i = 0; i < nRandom; i++) {
    x = random()*160 + 10;    // 區域X: [10,170]
    y = random()*160 + 10;    // 區域Y: [10,170]
    makeOval(x - pointRadius, y - pointRadius, pointRadius*2, pointRadius*2);
    fill();
}

// -------------------- 區域2:密集群聚 --------------------
nClusters = 3;
pointsPerCluster = 20;
for (c = 0; c < nClusters; c++) {
    cx = 200 + c * 30 + random()*10; // 區域X: 約在 200-300
    cy = 60 + random()*60;
    for (i = 0; i < pointsPerCluster; i++) {
        dx = random()*20 - 10;
        dy = random()*20 - 10;
        x = cx + dx;
        y = cy + dy;
        makeOval(x - pointRadius, y - pointRadius, pointRadius*2, pointRadius*2);
        fill();
    }
}

// -------------------- 區域3:規則排列 --------------------
for (i = 0; i < 6; i++) {
    for (j = 0; j < 6; j++) {
        x = 350 + i * 20;
        y = 50 + j * 20;
        makeOval(x - pointRadius, y - pointRadius, pointRadius*2, pointRadius*2);
        fill();
    }
}

// 完成後進行二值化
run("Make Binary");

Top-hat 濾波

Top-hat 濾波是一種基於形態學開運算的背景校正與特徵增強方法,方法是:原圖 - 開運算結果,突顯比結構元素小的亮特徵(常用)。

主要應用

  • 背景分離/校正:移除不均勻照明、背景雜訊,讓前景物體更明顯。
  • 對比增強:提升小型亮(或暗)特徵的對比度。
  • 特徵提取:強調影像中特定大小的細節,便於後續分割或量測。

ImageJ 操作

  • Process > Filters > Top Hat...

結構元素半徑建議大於目標特徵,且小於背景變化尺度。

Macro 範例

run("Blobs (25K)");
run("Invert LUT");
run("Duplicate...", "title=topHat50");
run("Top Hat...", "radius=50");

imagej課程:做高斯差分Difference of Gaussian

Difference of Gaussian(DoG)

一種用來偵測亮點(spot)的常見方法,特別是在影像中物體呈現為圓形、亮、背景暗的情況下非常有效。

DoG 如何偵測 SPOT(亮點)?

DoG 是「Difference of Gaussian」的縮寫,即高斯差分,是用來近似 Laplacian of Gaussian的一種方法,但比 LoG 更快、計算上更省資源。

流程

  • 設定一個預期粒子直徑 d,根據圖像中粒子的外觀(例如細胞、點狀物)的大小手動設定。

  • 計算兩個不同模糊程度的高斯標準差,使用下面的公式計算兩個高斯模糊的 σ(標準差):這兩個 sigma 對應到不同的模糊程度:σ₁ 比較小,保留細節;σ₂ 比較大,模糊程度高。

\[ σ₁ = \frac{1}{1 + \sqrt{2}}⋅𝑑 \]
\[ σ₂ = \sqrt{2}⋅σ₁ \]
  • 進行高斯模糊與相減(DoG) 對原圖像各自套用 σ₁ 和 σ₂ 的高斯模糊。用 σ₁ 模糊結果減去 σ₂ 模糊結果,得到 DoG 圖像。這張圖會有清晰的局部極大值(local maxima),出現在亮點的中心位置。

亮點(Spot)的偵測

  1. 尋找局部極大值(Local Maxima)對 DoG 圖像進行極大值搜尋,這些就是候選亮點。每個亮點會被指派一個「品質指標(quality)」,即 DoG 值的強度。

  2. 距離過近者去除,如果兩個亮點的距離小於 𝑑/2,則刪除品質較差的那一個。

  3. 進行次像素定位(Sub-pixel localization)使用拋物線內插法(parabolic interpolation),讓亮點的位置更精確。

去除錯誤亮點(Spurious spots)

  1. 以 quality threshold 篩選。設定一個品質閾值,低於此閾值的亮點會被排除,只保留真正可信的亮點。

優點

  • 快速近似 LoG,但運算效能更好。
  • 適合固定大小的亮點(即單一尺度)。
  • 可處理 2D 和 3D 影像。

使用時機

  1. 細胞核、粒線體、斑點蛋白等亮點分析
  2. 固定大小,且相對圓的結構
  3. 影像背景為暗,物件明亮者(高SNR)
// ==== 使用者設定參數 ====
// 預期的粒子直徑 (像素),這個值會用來推算兩個 Gaussian 模糊的程度
particle_diameter = 40;

// 設定 Find Maxima 的強度閾值,過濾掉太弱的亮點
quality_threshold = 10;


// ==== 推導參數 ====
// sigma1 與 sigma2 是 DoG (Difference of Gaussians) 所需的兩個不同 sigma
sigma1 = particle_diameter / (1 + sqrt(2));
sigma2 = sqrt(2) * sigma1;


// ==== 建立測試影像與反相處理 ====
// 產生 ImageJ 內建的 dot test image
run("Dot Blot");

// 將影像反相,讓亮點變成白點(方便找 maxima)
run("Invert");


// ==== 複製原始影像供後續處理 ====
// 備份目前影像為 "Original"
run("Duplicate...", "title=Original");
rename("Original");


// ==== 對影像做第一次 Gaussian 模糊(sigma1)====
run("Duplicate...", "title=Blur1");
run("Gaussian Blur...", "sigma=" + sigma1);


// ==== 對影像做第二次 Gaussian 模糊(sigma2)====
// 從原始影像再複製一次為 "Blur2"
selectWindow("Original");
run("Duplicate...", "title=Blur2");
run("Gaussian Blur...", "sigma=" + sigma2);


// ==== 兩張模糊影像相減,產生 DoG ====
// 計算 Blur1 - Blur2,將結果命名為 DoG
imageCalculator("Subtract create", "Blur1", "Blur2");
rename("DoG");


// ==== 找出 DoG 圖中的亮點中心 ====
// 使用 Find Maxima 找出顯著的亮點位置
run("Find Maxima...", "prominence="+ quality_threshold +" output=[Point Selection]");


// ==== ROI manager ====
// 清空 ROI manager
roiManager("Reset");

// 把目前偵測到的亮點選區加到 ROI manager
roiManager("Add");


// ==== 在原始影像中顯示這些點選區 ====
// 切換回 "Original" 視窗
selectWindow("Original");

// 選擇剛剛儲存到 ROI manager
roiManager("Select", 0);


// ==== 清理中間影像====
// 關閉中介處理影像視窗
selectWindow("Blur1"); close();
selectWindow("Blur2"); close();
selectWindow("DoG"); close();