/* - WEKA-FISH V2 - Fiji
* - Virginia Polytechnic Institute and State University
* - Biocomplexity Institute - Hauf Lab
* - Erod Keaton Baybay
*
* Disclaimer:
* Way more comments than necessary are in use for educational, self-teaching, self-referencing purposes.
* Because Erod is extremely forgetful, and tends to forget what certain things do.
*
* Note that the cleanAll() function will close images without saving.
* Please save your work prior to running this Macro.
*/
requires("1.52e"); // Required FIJI Version
var WFv = "1.0"; // WEKA-FISH Pipeline Version
macro "WEKA-FISH"
{
cleanAll();
showMessageWithCancel("WEKA-FISH Outliner "+WFv, ""
+"
WEKA-FISH Outliner
"
+"Hauf Lab - Biocomplexity Institute 2018"
+""
+"- MAcro Version: "+WFv
+"
- FIJI Version Required: 1.52e"
+"
- Designed for FISHquant v3a (MATLAB 2016b)"
+"
"
+"[Erod Keaton Baybay - erodb@vt.edu]");
// Default Parameters
limitSize = 5;
// ------- Initialization I - File Designation -----------------------------------------------------------------------
showStatus("Initializing WEKA-FISH...");
run("Set Measurements...", "area centroid fit display redirect=None decimal=3");
showStatus("Initializing WEKA-FISH... [Raw Image]");
waitForUser("Please select a Raw Image (FISHRed)");
RAWimage = File.openDialog("Choose Raw Image");
showStatus("Initializing WEKA-FISH... [ROI File]");
waitForUser("Please select an unfiltered ROI zip file");
ROIzip = File.openDialog("Choose ROI File");
open(RAWimage);
roiManager("Open",ROIzip);
print("[Outliner]");
print("Image: "+RAWimage);
deleteList = newArray();
imageWidth = getWidth();
imageHeight = getHeight();
topLimit = limitSize;
bottomLimit = imageHeight - limitSize;
leftLimit = limitSize;
rightLimit = imageWidth - limitSize;
run("Text Window...", "name=[Outline] width=100 height=50 monospaced");
print("[Outline]","\\Update:");
print("[Outline]", "FISH-QUANT\t");
print("[Outline]", "\nFile-version\t");
print("[Outline]", "\nRESULTS OF SPOT DETECTION PERFORMED ON\t");
print("[Outline]", "\nCOMMENT Automated outline definition (batch or quick-save)");
print("[Outline]", "\nIMG_Raw\t");
print("[Outline]", "\nIMG_Filtered\t");
print("[Outline]", "\nIMG_DAPI\t");
print("[Outline]", "\nIMG_TS_label\t");
print("[Outline]", "\nFILE_settings");
print("[Outline]", "\nPARAMETERS");
print("[Outline]", "\nPix-XY\tPix-Z\tRI\tEx\tEm\tNA\tType");
print("[Outline]", "\n-\t-\t-\t-\t-\t-\t-");
n = countROIs('C'); // Recount Cells
m = roiManager("count") - n;
for (i = 0; i < n; i++)
{
x_cell = newArray();
y_cell = newArray();
showStatus("Pairing ROIs...");
showProgress(i, n-1);
roiManager("Select", i);
roiManager("Set Line Width", 4);
getSelectionCoordinates(x_cell, y_cell);
nuclearIndex = newArray();
if (neg(x_cell, leftLimit, rightLimit) && neg(y_cell, topLimit, bottomLimit))
{
print("[Outline]", "\nCELL_START\t"+call("ij.plugin.frame.RoiManager.getName", i));
print("[Outline]", "\nX_POS\t"+tsv(x_cell));
print("[Outline]", "\nY_POS\t"+tsv(y_cell));
print("[Outline]", "\nZ_POS\t");
print("[Outline]", "\nCELL_END");
for (j = 0; j < m; j++)
{
x_nucleus = newArray();
y_nucleus = newArray();
k = n+j;
roiManager("Select", newArray(i,k));
roiManager("AND");
if ((i!=k)&&(selectionType>-1))
{
roiManager("Select", k);
getSelectionCoordinates(x_nucleus, y_nucleus);
if (neg(x_nucleus, leftLimit, rightLimit) && neg(y_nucleus, topLimit, bottomLimit))
{
nuclearIndex = append(nuclearIndex,k);
}
}
}
if (nuclearIndex.length == 1)
{
roiManager("Select", nuclearIndex[0]);
roiManager("Rename", "Single_"+call("ij.plugin.frame.RoiManager.getName", i)+"_Nucleus");
getSelectionCoordinates(x_nucleus, y_nucleus);
print("[Outline]", "\nNucleus_START\t"+call("ij.plugin.frame.RoiManager.getName", nuclearIndex[0]));
print("[Outline]", "\nX_POS\t"+tsv(x_nucleus));
print("[Outline]", "\nY_POS\t"+tsv(y_nucleus));
print("[Outline]", "\nZ_POS\t\t\t");
print("[Outline]", "\nNucleus_END");
}
else if (nuclearIndex.length == 2)
{
// Merging Two Nuclei
roiManager("Select", nuclearIndex[0]);
getSelectionCoordinates(xa, ya);
roiManager("Select", nuclearIndex[1]);
getSelectionCoordinates(xb, yb);
arr = mergeROIs(xa,ya,xb,yb);
mergex = newArray(xa.length+xb.length+2);
mergey = newArray(ya.length+yb.length+2);
xbNew = cycle(xb,arr[5]);
ybNew = cycle(yb,arr[5]);
for (v = 0; v < arr[2]; v++)
{
mergex[v] = xa[v];
mergey[v] = ya[v];
}
for (v = 0; v < xbNew.length; v++)
{
mergex[arr[2]+v] = xbNew[v];
mergey[arr[2]+v] = ybNew[v];
}
mergex[arr[2]+xbNew.length] = mergex[arr[2]];
mergey[arr[2]+ybNew.length] = mergey[arr[2]];
for(v = 0; v < (xa.length - arr[2]); v++)
{
mergex[arr[2]+xbNew.length+1+v] = xa[arr[2]-1+v];
mergey[arr[2]+ybNew.length+1+v] = ya[arr[2]-1+v];
}
mergex[xb.length+xa.length+1] = xa[xa.length-1];
mergey[xb.length+xa.length+1] = ya[xa.length-1];
roiManager("Select", nuclearIndex[0]);
makeSelection("trace", mergex, mergey);
roiManager("Update");
roiManager("Rename", "Merged_"+call("ij.plugin.frame.RoiManager.getName", i)+"_Nucleus");
roiManager("Set Color", "magenta");
roiManager("Set Line Width", 2);
deleteList = append(deleteList, nuclearIndex[1]);
print("[Outline]", "\nNucleus_START\t"+call("ij.plugin.frame.RoiManager.getName", nuclearIndex[0]));
print("[Outline]", "\nX_POS\t"+tsv(mergex));
print("[Outline]", "\nY_POS\t"+tsv(mergey));
print("[Outline]", "\nZ_POS\t\t\t");
print("[Outline]", "\nNucleus_END");
}
}
else
{
// Edge Cell Markup
roiManager("Set Color", "red");
roiManager("Set Line Width", 4);
deleteList = append(deleteList, i);
}
}
for (r = 0; r < roiManager("Count"); r++)
{
// Exclusion Cleanup
showStatus("Deleting Excluded ROIs...");
roiManager("Select", r);
if (startsWith(call("ij.plugin.frame.RoiManager.getName", r),'N'))
{
deleteList = append(deleteList, r);
}
}
print("[Outline]", "\n");
image = getTitle;
// Delete Redundant and Excluded ROIs
roiManager("Select", deleteList);
roiManager("Delete");
run("Clear Results");
n = countROIs('C'); // Recount Cells
m = roiManager("count") - n;
roiManager("Select",Array.reverse(Array.trim(Array.reverse(Array.getSequence(roiManager("Count"))), m)));
print("\n[Nucleus Pairing Report]");
print("Total Cells: " + n);
print("Cells - Single Nuclei: " + countROIs("S")+" ("+d2s((countROIs("S")/n*100),3)+"%)");
print("Cells - Merged Nuclei: " + countROIs("M")+" ("+d2s((countROIs("M")/n*100),3)+"%)");
roiManager("Reset");
close('*');
waitForUser("Outline Generation Complete\n Please save Log and Outline file.");
}
// ------- Function Bank ----------------------------------------------------------------------------------------
// Clean Up Function
function cleanAll()
{
close('*');
run("Clear Results");
roiManager("Reset");
print("\\Clear");
}
// Append to Array Function
function append(arr, value)
{
arr2 = newArray(arr.length+1);
for (i=0; i upper)
qual = false;
}
return qual;
}
// Cycles Values to Index
function cycle(arr, index)
{
n = arr.length;
cycledArray = newArray(n);
if (index < n)
{
for (i = index; i < n; i++)
cycledArray[i-index] = arr[i];
for (i = 0; i < index; i++)
cycledArray[n+i-index] = arr[i];
}
return cycledArray;
}
// Find Bridging Coordinates
function mergeROIs(x1,y1,x2,y2)
{
index1 = 0;
index2 = 0;
bestDistance = 50000; // Some arbitrary large number
result = newArray(7);
if ((x1.length == y1.length) && (x2.length == y2.length))
{
for (i = 0; i < x1.length; i++)
{
for (j = 0; j < x2.length; j++)
{
distance = sqrt(pow(x1[i]-x2[j],2)+pow(y1[i]-y2[j],2));
if (distance < bestDistance)
{
bestDistance = distance;
result[0] = x1[i];
result[1] = y1[i];
result[2] = i;
result[3] = x2[j];
result[4] = y2[j];
result[5] = j;
result[6] = bestDistance;
}
}
}
}
return result;
}
// Count ROIs with Matching First Letter
function countROIs(firstLetter)
{
ping = NaN;
n = roiManager("Count");
for (i = 0; i < n; i++)
{
if (startsWith(call("ij.plugin.frame.RoiManager.getName", i),firstLetter))
{
if (isNaN(ping))
ping = 1;
else
ping++;
}
}
return ping;
}
// Debug Intervene Function - Add inbetween lines to Debug
function intervene()
{
waitForUser("Macro has been halted for debugging.");
}