You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FIJI/ImageJ宏仅保存半数Analyze Particles结果与汇总表问题求助

问题描述

我有一个包含多张Tif图像的文件夹,计划使用ImageJ的Analyze Particles功能分析粒子。需要对单个通道的所有z-stack切片进行分析并保存结果至指定文件夹,但当前仅能保存每隔一个切片的汇总表和结果表(例如10个切片仅保存1、3、5、7…),请排查宏代码问题。

原宏代码:

// Choose input and output folders
dir1 = getDirectory("Choose Source Directory ");
resultsDir = dir1+"results/";
File.makeDirectory(resultsDir);
dir2 = getDirectory("Choose Destination Directory ");
list = getFileList(dir1);

processFolder(dir1);
function processFolder(dir1){
    list = getFileList(dir1);
    list = Array.sort(list);
    for (i = 0; i < list.length; i++) {
        if(File.isDirectory(dir1 + File.separator + list[i]))
            processFolder(dir1 + File.separator + list[i]);
        if(endsWith(list[i], ".tif"))
            processFile(dir1, dir2, list[i]);
    }
}    

function processFile(dir1, dir2, file){
    open(dir1 + File.separator + file);
    
    
// Split channels and rename     
title = getTitle();
run("Split Channels");
selectWindow("C2-" + title);
rename("live");
selectWindow("C3-" + title);
rename("dead");
selectWindow("C4-" + title);
rename("total");



//Apply pre-processing filters and threshold live cells
selectWindow("live");
run("Duplicate...", "duplicate"); // Duplicates live channel so accurate thresholding can be done in the following step
rename("duplicate");
selectWindow("live");
run("Gaussian Blur...", "sigma=2 stack");
run("Threshold...");
waitForUser("Adjust threshold, press ok on this pop-up when the threshold has been set. Do not press anything on the threshold screen when finished. Just press ok on action required screen");
run("Make Binary", "method=Default background=Dark calculate black");
//run("Auto Local Threshold", "method=Phansalkar radius=8 parameter_1=0 parameter_2=0 white stack");
run("Fill Holes", "stack");
//run("Watershed", "stack");
run("Stack to Images"); //Makes z-slices individual images



//For every image that is binary, rename the slice and analyze particles
for(z=0; z<nImages; z++){
            selectImage(z+1);
        if(is("binary")){
            name = getTitle();
            rename(name + "_" + title);
            run("Analyze Particles...", "size=0.50-Infinity show=[Overlay Masks] display clear summarize overlay add");
            selectWindow("Summary");
            saveAs("Results", dir2 + "Live_Summary_" + z + "_" + title + ".csv");
            selectWindow("Results");
            saveAs("Results", dir2  + name +"_" + z + "_" + title + ".csv"); 
            close();
        }
    }       
        close("live*");
        close("duplicate");
        run("Close");
        close();
        // Leave the print statements until things work, then remove them.
    print("Processing: " + dir1 + File.separator + file);
    print("Saving to: " + dir2);
}
问题根源
  1. 索引错位:循环中处理完切片后执行close()关闭当前图像,导致后续selectImage(z+1)选中的不是预期切片。比如关闭第1张后,原第2张变为第1张,下一次循环选第2张实际是原第3张,最终只处理奇数位切片。
  2. 冗余判断干扰:is("binary")判断完全多余——拆分出的所有切片都是从二值化后的栈生成的,该判断可能因窗口切换误判跳过部分切片。
修复方案
// 选择输入和输出文件夹
dir1 = getDirectory("Choose Source Directory ");
resultsDir = dir1+"results/";
File.makeDirectory(resultsDir);
dir2 = getDirectory("Choose Destination Directory ");
list = getFileList(dir1);

processFolder(dir1);
function processFolder(dir1){
    list = getFileList(dir1);
    list = Array.sort(list);
    for (i = 0; i < list.length; i++) {
        if(File.isDirectory(dir1 + File.separator + list[i]))
            processFolder(dir1 + File.separator + list[i]);
        if(endsWith(list[i], ".tif"))
            processFile(dir1, dir2, list[i]);
    }
}    

function processFile(dir1, dir2, file){
    open(dir1 + File.separator + file);
    
    // 拆分通道并重命名     
    title = getTitle();
    run("Split Channels");
    selectWindow("C2-" + title);
    rename("live");
    selectWindow("C3-" + title);
    rename("dead");
    selectWindow("C4-" + title);
    rename("total");

    // 对live通道进行预处理和阈值化
    selectWindow("live");
    run("Duplicate...", "duplicate"); // 复制live通道用于后续阈值处理
    rename("duplicate");
    selectWindow("live");
    run("Gaussian Blur...", "sigma=2 stack");
    run("Threshold...");
    waitForUser("调整阈值,设置完成后点击此弹窗的OK。阈值窗口操作完成后无需额外操作,仅需点击本提示窗口的OK");
    run("Make Binary", "method=Default background=Dark calculate black");
    //run("Auto Local Threshold", "method=Phansalkar radius=8 parameter_1=0 parameter_2=0 white stack");
    run("Fill Holes", "stack");
    //run("Watershed", "stack");
    run("Stack to Images"); // 将z-stack拆分为独立图像

    // 提前记录所有切片标题,避免索引错位
    sliceCount = nImages;
    sliceTitles = newArray(sliceCount);
    for(z=0; z<sliceCount; z++){
        selectImage(z+1);
        sliceTitles[z] = getTitle();
    }

    // 遍历所有切片分析粒子
    for(z=0; z<sliceCount; z++){
        selectWindow(sliceTitles[z]);
        rename(sliceTitles[z] + "_" + title);
        run("Analyze Particles...", "size=0.50-Infinity show=[Overlay Masks] display clear summarize overlay add");
        
        // 保存汇总表并关闭窗口
        selectWindow("Summary");
        saveAs("Results", dir2 + "Live_Summary_" + z + "_" + title + ".csv");
        close("Summary");
        
        // 保存结果表并关闭窗口
        selectWindow("Results");
        saveAs("Results", dir2 + sliceTitles[z] + "_" + z + "_" + title + ".csv");
        close("Results");
    }       

    // 批量清理所有相关窗口
    close("live*");
    close("duplicate");
    close("dead");
    close("total");
    close(title);

    // 打印处理日志
    print("Processing: " + dir1 + File.separator + file);
    print("Saving to: " + dir2);
}
修复说明
  • 提前记录所有切片的标题,通过标题选中窗口,彻底避免索引错位问题
  • 移除冗余的is("binary")判断,确保所有切片都被处理
  • 每次处理后及时关闭Summary和Results窗口,避免窗口堆积干扰后续操作
  • 统一在最后批量关闭所有图像窗口,逻辑更清晰

内容的提问来源于stack exchange,提问作者MM1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:14:56