/* Grow skeleton to join adjacent limbs . . . 1 pixel at a time Uses Gabriel Landini's skeletonization algorithm, different from the one in ImageJ similar to skeleton1 but 4-connected 3 Dec 2003 uses BinaryThin2_.class available from http://www.mecourse.com/landinig/software/software.html v210723 1st version PJL NHMFL v211025 Updated function v211104: Updated stripKnownExtensionFromString function 211112 + 220616 + 230505 + v230607: Again */ macroL = "Grow_Skeleton_v211112-f3.ijm"; saveSettings; if (is("binary")==false) exit("This first version seems to work best if the image in binary, goodbye"); getStatistics(null, meanI, null, null, null, null); getDimensions(imageWidth, imageHeight, imageChannels, imageSlices, imageFrames); originalTitle = stripKnownExtensionFromString(getTitle()); if (meanI < 128) blackSkel = false; else blackSkel = true; skelParameters = "kernel_a='1 1 1 2 1 2 0 0 0 ' kernel_b='2 1 1 0 1 1 0 0 2 ' rotations='rotate 45' iterations=&reRSkelI"; /* 1st cleanup diagonals */ if (blackSkel) skelParameters += " black"; else skelParameters += " white"; run("Options...", "iterations=1 count=1 do=Nothing"); Dialog.create(macroL + ": options"); Dialog.addRadioButtonGroup("Save options: ",newArray("Overwrite", "New_Image","Animation_Stack"),1,3,"New_Image"); Dialog.addNumber("How many iterations?", 10,0,5,"pixels"); Dialog.addCheckbox("Precede expansion with binary close?", true); Dialog.addNumber("Limit re-skeltonize cleanup? /(-1 is until idempotence reached/)", -1); Dialog.addNumber("Pause frame to watch it grow?",0,0,5,"mS"); // Dialog.addCheckbox("For animation stack only show differences in each successive slice?", true); Dialog.show(); output = Dialog.getRadioButton(); expansions = Dialog.getNumber(); preclose = Dialog.getCheckbox(); reRSkelI = Dialog.getNumber(); pauseF = Dialog.getNumber(); // diceSlice = Dialog.getCheckbox(); if(pauseF==0) setBatchMode(true); if (output!="Overwrite"){ newTitle = originalTitle + "_aSkelGrow" + expansions; lT = lengthOf(newTitle); if (lT > 32) newTitle = substring(newTitle,0,14) + "..." + substring(newTitle,lT-14,lT); run("Duplicate...",newTitle); rotCounter = 0; for(i = 1; i0) wait(pauseF); } // if (output=="Animation_Stack" && diceSlice){ // /* Subtracts each slice in a stack from the next, successively through the stack to reveals pixels regions that have // changed in value from slice to slice. Author: Jacob Pruess https://imagej.net/macros/Slice-to-Slice%20Difference.txt // Unfortunately this does not work here because of the rotational jitter // */ // setPasteMode("Subtract"); // run("Set Slice...", "slice="+nSlices); // stackTitle = getTitle(); // run("Duplicate...", "duplicate range="+nSlices); // rename(newTitle + "_Final"); // selectWindow(stackTitle); // run("Set Slice...", "slice="+nSlices); // run("Select All"); // for(i=1; i]"); // run("Next Slice [>]"); // run("Paste"); // run("Invert", "slice"); // run("Previous Slice [<]"); // } // setPasteMode("Copy"); /* restore default paste mode */ // run("Select None"); // } if(pauseF==0) setBatchMode("exit & display"); /* Probably not necessary if exiting gracefully but otherwise harmless */ beep(); wait(300); beep(); wait(300); beep(); restoreSettings; call("java.lang.System.gc"); /* force a garbage collection */ showStatus(macroL + " Finished: " + expansions + " expansions applied"); /* ( 8(|) ( 8(|) All ASC Functions @@@@@:-) @@@@@:-) */ function stripKnownExtensionFromString(string) { /* Note: Do not use on path as it may change the directory names v210924: Tries to make sure string stays as string. v211014: Adds some additional cleanup. v211025: fixes multiple 'known's issue. v211101: Added ".Ext_" removal. v211104: Restricts cleanup to end of string to reduce risk of corrupting path. v211112: Tries to fix trapped extension before channel listing. Adds xlsx extension. v220615: Tries to fix the fix for the trapped extensions ... v230504: Protects directory path if included in string. Only removes doubled spaces and lines. v230505: Unwanted dupes replaced by unusefulCombos. v230607: Quick fix for infinite loop on one of while statements. v230614: Added AVI. v230905: Better fix for infinite loop. v230914: Added BMP and "_transp" and rearranged */ fS = File.separator; string = "" + string; protectedPathEnd = lastIndexOf(string,fS)+1; if (protectedPathEnd>0){ protectedPath = substring(string,0,protectedPathEnd); string = substring(string,protectedPathEnd); } unusefulCombos = newArray("-", "_"," "); for (i=0; i=0) string = replace(string,combo,unusefulCombos[i]); } } if (lastIndexOf(string, ".")>0 || lastIndexOf(string, "_lzw")>0) { knownExts = newArray(".avi", ".csv", ".bmp", ".dsx", ".gif", ".jpg", ".jpeg", ".jp2", ".png", ".tif", ".txt", ".xlsx"); knownExts = Array.concat(knownExts,knownExts,"_transp","_lzw"); kEL = knownExts.length; for (i=0; i0){ preChan = substring(string,0,iChanLabels); postChan = substring(string,iChanLabels); while (indexOf(preChan,knownExts[i])>0){ preChan = replace(preChan,knownExts[i],""); string = preChan + postChan; } } } while (endsWith(string,knownExts[i])) string = "" + substring(string, 0, lastIndexOf(string, knownExts[i])); } } unwantedSuffixes = newArray(" ", "_","-"); for (i=0; i0){ if(!endsWith(protectedPath,fS)) protectedPath += fS; string = protectedPath + string; } return string; }