requires("1.54p"); macro "Batch_C2_Phalloidin_AreaPerNucleus_v9_FixedThreshold_Conservative_WithBatchSummary" { // ========================================================= // DEFAULT PARAMETERS // ========================================================= rollingBallCell = 80; gaussianSigmaCell = 1.0; minThreshold = 15; maxThreshold = 255; minPhalloidinArea = 200; excludeEdges = false; saveOverlay = true; fontSizeLabel = 18; // ========================================================= // SELECT FOLDERS // ========================================================= c2Dir = getDirectory("Cartella immagini C2 falloidina"); if (c2Dir == "") exit("Nessuna cartella C2 selezionata."); roiDir = getDirectory("Cartella ROI nuclei"); if (roiDir == "") exit("Nessuna cartella ROI selezionata."); outDir = getDirectory("Cartella output"); if (outDir == "") exit("Nessuna cartella output selezionata."); if (!endsWith(c2Dir, "/")) c2Dir = c2Dir + "/"; if (!endsWith(roiDir, "/")) roiDir = roiDir + "/"; if (!endsWith(outDir, "/")) outDir = outDir + "/"; // ========================================================= // PARAMETER DIALOG // ========================================================= Dialog.create("C2 falloidina - area per nucleo"); Dialog.addNumber("Rolling ball", rollingBallCell); Dialog.addNumber("Gaussian sigma", gaussianSigmaCell); Dialog.addNumber("Min threshold (fixed)", minThreshold); Dialog.addNumber("Max threshold (fixed)", maxThreshold); Dialog.addNumber("Min phalloidin particle area", minPhalloidinArea); Dialog.addCheckbox("Exclude edge particles", excludeEdges); Dialog.addCheckbox("Save overlay", saveOverlay); Dialog.addNumber("Overlay font size", fontSizeLabel); Dialog.show(); rollingBallCell = Dialog.getNumber(); gaussianSigmaCell = Dialog.getNumber(); minThreshold = Dialog.getNumber(); maxThreshold = Dialog.getNumber(); minPhalloidinArea = Dialog.getNumber(); excludeEdges = Dialog.getCheckbox(); saveOverlay = Dialog.getCheckbox(); fontSizeLabel = Dialog.getNumber(); fileList = getFileList(c2Dir); // ========================================================= // PREPARE BATCH SUMMARY CSV // ========================================================= batchSummaryCsv = outDir + "Batch_C2_PhalloidinArea_per_nucleus_summary.csv"; batchHeader = "Sample_ID," + "Phalloidin_area_per_nucleus," + "Phalloidin_SD_area_divided_by_nuclei," + "Nuclei_count," + "Phalloidin_particles," + "Phalloidin_total_area," + "Phalloidin_mean_area," + "Phalloidin_SD_area," + "Phalloidin_CV_area," + "Phalloidin_min_area," + "Phalloidin_max_area," + "Min_threshold_fixed," + "Max_threshold_fixed\n"; File.saveString(batchHeader, batchSummaryCsv); // ========================================================= // LOOP FILES // ========================================================= for (f = 0; f < fileList.length; f++) { name = fileList[f]; path = c2Dir + name; if (File.isDirectory(path)) continue; if (!(endsWith(name, "_C2.tif") || endsWith(name, "_C2.tiff") || endsWith(name, "_C2.TIF") || endsWith(name, "_C2.TIFF"))) continue; open(path); originalTitle = getTitle(); run("Select None"); roiManager("Reset"); // ----------------------------------------------------- // BASE NAME // ----------------------------------------------------- baseName = originalTitle; if (endsWith(baseName, ".tif") || endsWith(baseName, ".TIF")) baseName = substring(baseName, 0, lengthOf(baseName) - 4); else if (endsWith(baseName, ".tiff") || endsWith(baseName, ".TIFF")) baseName = substring(baseName, 0, lengthOf(baseName) - 5); if (endsWith(baseName, "_C2")) sampleBase = substring(baseName, 0, lengthOf(baseName) - 3); else sampleBase = baseName; roiZip = roiDir + sampleBase + "_C1_Nuclei_ROIs.zip"; if (!File.exists(roiZip)) { print("ROI nuclei non trovate: " + sampleBase); close(); continue; } summaryCsv = outDir + sampleBase + "_C2_PhalloidinArea_per_nucleus.csv"; overlayTif = outDir + sampleBase + "_C2_PhalloidinMask_with_Nuclei.tif"; phalloidinRoiZip = outDir + sampleBase + "_C2_Phalloidin_ROIs.zip"; // ----------------------------------------------------- // PREPARE IMAGE // ----------------------------------------------------- Stack.getDimensions(w, h, c, z, t); if (z > 1) { run("Z Project...", "projection=[Max Intensity]"); rename("C2_MAX"); selectWindow(originalTitle); close(); } else { rename("C2_MAX"); } selectWindow("C2_MAX"); run("Select None"); run("Duplicate...", "title=C2_OVERLAY_BASE"); // ----------------------------------------------------- // COUNT NUCLEI FROM ROI ZIP // ----------------------------------------------------- roiManager("Reset"); roiManager("Open", roiZip); nucleiCount = roiManager("count"); if (nucleiCount == 0) { print("Nessuna ROI nucleo in: " + roiZip); close("*"); roiManager("Reset"); continue; } // ----------------------------------------------------- // SEGMENT PHALLOIDIN - CONSERVATIVE // ----------------------------------------------------- selectWindow("C2_MAX"); run("Select None"); run("Duplicate...", "title=C2_SEG"); selectWindow("C2_SEG"); run("8-bit"); run("Subtract Background...", "rolling=" + rollingBallCell); if (gaussianSigmaCell > 0) run("Gaussian Blur...", "sigma=" + gaussianSigmaCell); run("Enhance Contrast...", "saturated=1.0 normalize"); setThreshold(minThreshold, maxThreshold); setOption("BlackBackground", false); run("Convert to Mask"); // Pulizia leggera, più conservativa delle operazioni morfologiche run("Despeckle"); rename("PHALLOIDIN_MASK"); // ----------------------------------------------------- // MEASURE TOTAL PHALLOIDIN AREA + SAVE PHALLOIDIN ROIs // ----------------------------------------------------- roiManager("Reset"); if (isOpen("Results")) { selectWindow("Results"); run("Clear Results"); } run("Set Measurements...", "area decimal=3"); options = "size=" + minPhalloidinArea + "-Infinity circularity=0.00-1.00 display clear add"; if (excludeEdges) options = options + " exclude"; run("Analyze Particles...", options); nParts = nResults; totalPhalloidinArea = 0; areas = newArray(nParts); for (i = 0; i < nParts; i++) { a = getResult("Area", i); totalPhalloidinArea += a; areas[i] = a; } if (nParts > 0) { Array.getStatistics(areas, minA, maxA, meanA, sdA); roiManager("Deselect"); roiManager("Save", phalloidinRoiZip); } else { minA = 0; maxA = 0; meanA = 0; sdA = 0; } phalloidinAreaPerNucleus = totalPhalloidinArea / nucleiCount; sdAreaDividedByNuclei = sdA / nucleiCount; if (meanA > 0) cvArea = sdA / meanA; else cvArea = 0; // ----------------------------------------------------- // SAVE SINGLE-IMAGE SUMMARY CSV // ----------------------------------------------------- if (isOpen("Results")) { selectWindow("Results"); run("Clear Results"); } setResult("Sample_ID", 0, sampleBase); setResult("Phalloidin_area_per_nucleus", 0, phalloidinAreaPerNucleus); setResult("Phalloidin_SD_area_divided_by_nuclei", 0, sdAreaDividedByNuclei); setResult("Nuclei_count", 0, nucleiCount); setResult("Phalloidin_particles", 0, nParts); setResult("Phalloidin_total_area", 0, totalPhalloidinArea); setResult("Phalloidin_mean_area", 0, meanA); setResult("Phalloidin_SD_area", 0, sdA); setResult("Phalloidin_CV_area", 0, cvArea); setResult("Phalloidin_min_area", 0, minA); setResult("Phalloidin_max_area", 0, maxA); setResult("Min_threshold_fixed", 0, minThreshold); setResult("Max_threshold_fixed", 0, maxThreshold); updateResults(); saveAs("Results", summaryCsv); // ----------------------------------------------------- // APPEND TO BATCH SUMMARY CSV // ----------------------------------------------------- batchLine = sampleBase + "," + d2s(phalloidinAreaPerNucleus, 6) + "," + d2s(sdAreaDividedByNuclei, 6) + "," + nucleiCount + "," + nParts + "," + d2s(totalPhalloidinArea, 6) + "," + d2s(meanA, 6) + "," + d2s(sdA, 6) + "," + d2s(cvArea, 6) + "," + d2s(minA, 6) + "," + d2s(maxA, 6) + "," + minThreshold + "," + maxThreshold + "\n"; File.append(batchLine, batchSummaryCsv); // ----------------------------------------------------- // SAVE OVERLAY WITH PHALLOIDIN ROI + NUCLEI // ----------------------------------------------------- if (saveOverlay) { // base image selectWindow("C2_OVERLAY_BASE"); run("RGB Color"); // show phalloidin ROIs in green roiManager("Reset"); if (File.exists(phalloidinRoiZip)) roiManager("Open", phalloidinRoiZip); roiManager("Deselect"); roiManager("Set Color", "green"); roiManager("Show All"); run("Flatten"); rename("OVERLAY_PHALLOIDIN"); // add nuclei in magenta roiManager("Reset"); roiManager("Open", roiZip); selectWindow("OVERLAY_PHALLOIDIN"); roiManager("Deselect"); roiManager("Set Color", "magenta"); roiManager("Show All with labels"); run("Flatten"); rename("FINAL_OVERLAY"); // add yellow text selectWindow("FINAL_OVERLAY"); setForegroundColor(255, 255, 0); setFont("SansSerif", fontSizeLabel, "antialiased"); drawString("Area/nucleus = " + d2s(phalloidinAreaPerNucleus, 2), 20, 30); drawString("SD/nuclei = " + d2s(sdAreaDividedByNuclei, 2), 20, 55); drawString("Nuclei = " + nucleiCount, 20, 80); drawString("CV = " + d2s(cvArea, 3), 20, 105); saveAs("Tiff", overlayTif); close(); if (isOpen("OVERLAY_PHALLOIDIN")) { selectWindow("OVERLAY_PHALLOIDIN"); close(); } } // ----------------------------------------------------- // CLEANUP // ----------------------------------------------------- close("*"); roiManager("Reset"); run("Collect Garbage"); } print("=== Batch C2 phalloidin area per nucleus completato ==="); print("Summary batch salvato in: " + batchSummaryCsv); }