Fiji/ImageJ 批量统计图片荧光信号:Split Channels、阈值分割与自动测量
在荧光显微镜图像分析中经常需要对大量图像执行相同的处理流程例如批量打开 PNG 图像分离 RGB 通道提取指定颜色通道根据设定的灰度范围进行 Threshold对图像进行测量将所有结果汇总并导出为 CSV 文件。手动完成这项工作繁重且枯燥我们可以利Fiji/ImageJ Macro 脚本.ijm可以自动完成整个流程。一、批量统计脚本使用整个分析流程如下Batch open images ↓ Split Channels ↓ Select Green channel ↓ Threshold ↓ Convert to Mask ↓ Measure ↓ Collect Results ↓ Export CSV脚本使用流程0. 首先在Fiji中手动确定要统计的通道颜色和阈值大小在.ijm脚本中填写相应超参数ptype文件类型channel_chosen选择的通道threshLow/threshHigh信号强度阈值打开Fiji找到Plugins-Macros-Run双击点开选择Fiji/ImageJ Macro 脚本.ijm打开选择待处理图片所在文件夹选择结果文件.csv输出位置即可实现批量统计结果还会自动保存在measure_results.csv中。二、脚本实现1. 脚本最开始设置了几个可修改核心参数// ------------------ Editable parameters (nothing hardcoded below) ------------------ ptype .png channel_chosen green threshLow 99; // Threshold lower bound threshHigh 255; // Threshold upper bound (separate variable from maxVal, adjust independently) // -------------------------------------------------------------------------------2. 批量读取图片// Pick input folder (contains the original .png files) inputDir getDirectory(Choose the input folder containing pictures); // Pick output folder (where the CSV result will be saved) outputDir getDirectory(Choose the output folder for the results CSV); fileList getFileList(inputDir); // Clear any leftover Results window before starting run(Clear Results); setBatchMode(true); // headless batch processing, faster, avoids window flicker count 0; for (i 0; i fileList.length; i) { fileName fileList[i]; // Only process files ending in .png if (endsWith(toLowerCase(fileName), ptype)) { path inputDir fileName; open(path); origTitle getTitle();3. 拆分并选择指定通道// Split channels (works for RGB or multi-channel stacks) run(Split Channels); // After Split Channels, window titles usually look like: // RGB image - originalName (red) / (green) / (blue) // Find the chosen-channel window by matching either naming pattern. titles getList(image.titles); chosen ; for (j 0; j titles.length; j) { t titles[j]; tLower toLowerCase(t); if (indexOf(tLower, channel_chosen) 0) { chosen t; } } if (chosen ) { // Could not find a chosen channel - skip this file to avoid wrong processing print(WARNING: could not find chosen channel in file fileName , skipping.); closeAllImages(); continue; } selectWindow(chosen);4. 应用设定阈值// setThreshold(low, high) selects pixels directly by gray value range, setThreshold(threshLow, threshHigh); // Actually apply the threshold, turning the image into a binary mask // (this is what clicking Apply in the Threshold dialog does) setOption(BlackBackground, true); run(Convert to Mask);5. 测量荧光强度并返回结果// Make sure Measure records what we need (area, mean, min/max gray value), // and limit restricts the measurement to the thresholded (selected) pixels only. run(Set Measurements..., area mean min integrated limit redirectNone decimal3); // Run Measure - result gets appended to the Results table run(Measure); // Record the filename in the last Results row for reference row nResults - 1; setResult(Filename, row, fileName); updateResults(); // Close all windows produced by this file to free memory closeAllImages();三、完整 Fiji/ImageJ Macro 脚本代码// // auto.ijm // Batch open pictures - Split Channels - take Blue channel // - set Threshold (threshLow~threshHigh) - Measure // Results are collected into the Results table and saved as CSV. // // NOTE: All prompts/log messages are in English on purpose. // Fijis Log window font does not render Chinese properly (shows // garbled/mojibake text), so English avoids that entirely. // // ------------------ Editable parameters (nothing hardcoded below) ------------------ ptype .png channel_chosen green threshLow 99; // Threshold lower bound threshHigh 255; // Threshold upper bound (separate variable from maxVal, adjust independently) // ------------------------------------------------------------------------------- // Pick input folder (contains the original .png files) inputDir getDirectory(Choose the input folder containing pictures); // Pick output folder (where the CSV result will be saved) outputDir getDirectory(Choose the output folder for the results CSV); fileList getFileList(inputDir); // Clear any leftover Results window before starting run(Clear Results); setBatchMode(true); // headless batch processing, faster, avoids window flicker count 0; for (i 0; i fileList.length; i) { fileName fileList[i]; // Only process files ending in .png if (endsWith(toLowerCase(fileName), ptype)) { path inputDir fileName; open(path); origTitle getTitle(); // Split channels (works for RGB or multi-channel stacks) run(Split Channels); // After Split Channels, window titles usually look like: // RGB image - originalName (red) / (green) / (blue) // Find the chosen-channel window by matching either naming pattern. titles getList(image.titles); chosen ; for (j 0; j titles.length; j) { t titles[j]; tLower toLowerCase(t); if (indexOf(tLower, channel_chosen) 0) { chosen t; } } if (chosen ) { // Could not find a chosen channel - skip this file to avoid wrong processing print(WARNING: could not find chosen channel in file fileName , skipping.); closeAllImages(); continue; } selectWindow(chosen); // setThreshold(low, high) selects pixels directly by gray value range, setThreshold(threshLow, threshHigh); // Actually apply the threshold, turning the image into a binary mask // (this is what clicking Apply in the Threshold dialog does) setOption(BlackBackground, true); run(Convert to Mask); // Make sure Measure records what we need (area, mean, min/max gray value), // and limit restricts the measurement to the thresholded (selected) pixels only. run(Set Measurements..., area mean min integrated limit redirectNone decimal3); // Run Measure - result gets appended to the Results table run(Measure); // Record the filename in the last Results row for reference row nResults - 1; setResult(Filename, row, fileName); updateResults(); count; // Close all windows produced by this file to free memory closeAllImages(); } } setBatchMode(false); // Save the combined results if (count 0) { outPath outputDir measure_results.csv; // Delete any existing file first to avoid an overwrite? prompt if (File.exists(outPath)) { File.delete(outPath); } saveAs(Results, outPath); print(Done. Processed count file(s). Results saved to: outPath); } else { print(No matching .png files found.); } // ------------------ Helper: close all currently open image windows ------------------ function closeAllImages() { while (nImages 0) { selectImage(nImages); close(); } }