macro "Clean up errors in skeleton" { /* Diagonals and trapped square block cleanup to ensure 4-way (fully) connected lines v200512 1st version PJL NHMFL v210727 Added dialog and a few more fixes Updated functions: 5/16/2022 3:38 PM v220818 Removed restoreExit. */ macroL = "Clean_up_Skeleton_v220818.ijm"; run("8-bit"); if (!is("binary")) { binaryChoice = getBoolean("Binary image required; run threshold?"); if(binaryChoice) { run("Threshold..."); waitForUser("Threshold complete?"); } else exit("Goodbye"); } if (is("Inverting LUT")) run("Invert LUT"); getStatistics(null, meanI, null, null, null, null); getDimensions(imageWidth, imageHeight, imageChannels, imageSlices, imageFrames); if (meanI < 128) blackSkel = false; else blackSkel = true; dFixes = 0; sFixes = 0; sPixels = 0; semiPixels = 0; dblWides = 0; if (checkForPlugin("morphology_collection")) morphMe = true; else morphMe = false; zoomOPC = 100*getZoom(); getLocationAndSize(xW, yW, widthW, heightW); Dialog.create("Clean up imageJ skeleton: " + macroL); Dialog.addCheckbox("Fix broken diagonals?",true); Dialog.addCheckbox("Fix trapped pixel squares?",true); Dialog.addCheckbox("Fill single pixel objects?",false); Dialog.addCheckbox("Fill diagonal-pixel trapped single pixel objects?",true); Dialog.addCheckbox("Fix most 2-pixel wide connections?",true); if (morphMe) Dialog.addNumber("Post-cleanup skeletonization? \(0 = No, -1 = Erode until idempotence\)", -1); Dialog.addCheckbox("Apply to copy of image or current selection?",true); Dialog.addCheckbox("Output fix report to log window?",false) Dialog.show(); diags = Dialog.getCheckbox(); pixies = Dialog.getCheckbox(); sPixel = Dialog.getCheckbox(); semiPixel = Dialog.getCheckbox(); dblWide = Dialog.getCheckbox(); if (morphMe){ erosions = Dialog.getNumber(); if (erosions==0) morphMe = false; } if(Dialog.getCheckbox()){ run("Duplicate...", " "); xW +=20; xY +=20; run("Set... ", "zoom=&zoomOPC x=&xW y=&xY"); } reportL = Dialog.getCheckbox; setBatchMode(true); if (blackSkel) run("Invert"); if (sPixel || semiPixel || dblWide){ for(i = 1; i=6){ mCount = 0; for (m=-1; m<2; m++) if (getPixel(i-1,j+m)==255) mCount++; if (mCount==3) setPixel(i-1,j,0); else { mCount = 0; for (m=-1; m<2; m++) if (getPixel(i+m,j-1)==255) mCount++; if (mCount==3){ setPixel(i,j-1,0); dblWides++; } else { for (m=-1; m<2; m++) if (getPixel(i+m,j+1)==255) mCount++; if (mCount==3){ setPixel(i,j+1,0); dblWides++; }else { for (m=-1; m<2; m++) if (getPixel(i+1,j+m)==255) mCount++; if (mCount==3){ setPixel(i+1,j,0); dblWides++; } } } } } } } } /* 1st cleanup diagonals */ if (diags){ for(i = 1; i0 || semiPixels>0){ if (sPixels>0) statusMessage += ", " + sPixels + " single pixels"; if (semiPixels>0) statusMessage += ", "+ semiPixels + " diagonally-trapped pixels"; statusMessage += " filled"; if (dblWides>0) statusMessage += ", "+ dblWides + " thick connectors thinned"; } if (reportL){ statusMessage = "" + macroL + " on " + getTitle() + ":\n" + statusMessage; print(statusMessage); showStatus(statusMessage); } /* ( 8(|) ( 8(|) All ASC Functions @@@@@:-) @@@@@:-) */ function checkForPlugin(pluginName) { /* v161102 changed to true-false v180831 some cleanup v210429 Expandable array version v220510 Looks for both class and jar if no extension is given v220818 Mystery issue fixed, no longer requires restoreExit */ pluginCheck = false; if (getDirectory("plugins") == "") print("Failure to find any plugins!"); else { pluginDir = getDirectory("plugins"); if (lastIndexOf(pluginName,".")==pluginName.length-1) pluginName = substring(pluginName,0,pluginName.length-1); pExts = newArray(".jar",".class"); knownExt = false; for (j=0; j