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); }
问题根源
- 索引错位:循环中处理完切片后执行
close()关闭当前图像,导致后续selectImage(z+1)选中的不是预期切片。比如关闭第1张后,原第2张变为第1张,下一次循环选第2张实际是原第3张,最终只处理奇数位切片。 - 冗余判断干扰:
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
相关产品推荐
相关产品推荐

