/* Demo of vertex angles N. Vischer, 18.03.17 11:30 */ macro "Vertex Angles of Segmented Line [1]"{ msg = "Angles (in degrees) are defined as \n"; msg += "'change of travel direction' along the contour \n \n"; msg += "Straight = 0, \nTurn-right = positive"; close("abc"); newImage("abc", "RGB white", 600, 500, 1); makeLine(20,250, 80, 260, 160, 290, 240, 320, 320, 320, 400, 400, 520, 400); getSelectionCoordinates(xx, yy); arm = 1; curvature = Array.getVertexAngles(xx, yy, arm); setColor("blue"); setFont("SansSerif", 14, "antialiased bold"); drawString(msg, 20, 30); for(jj = 1; jj < curvature.length - 1; jj++){ drawString(d2s(curvature[jj], 1), xx[jj], yy[jj]); } } macro "Explain 'Arm' [2]"{ close("abc"); newImage("abc", "8-bit white", 660, 660, 1); setColor(0, 0, 200); setFont("SansSerif", 16, "bold antialiased"); tv = 20;//top vertex for(arm = 1; arm <=3; arm++){ Overlay.clear; makeOval(80, 80, 480, 550); run("Interpolate", "interval=60 adjust"); run("Add Selection..."); roiManager("reset"); roiManager("add"); getSelectionCoordinates(xx, yy); angles = Array.getVertexAngles(xx, yy, arm); phi = angles[tv]; makeLine(xx[tv - arm], yy[tv - arm], xx[tv], yy[tv], xx[tv+arm], yy[tv+arm]); run("Properties... ", "stroke=red width=8"); run("Add Selection..."); roiManager("select", 0); Overlay.drawString("arm=" + arm + "\nangle=" + d2s(phi, 1) + " deg", xx[tv], yy[tv]-26); if(arm < 3) waitForUser("Click OK to increase 'arm'"); } } /* Sum of all vertex angles depends on contour direction 'Blob' contour clockwise: sum = 360 'Blob' contour counter-clockwise: sum = -360 '8' contour: sum = 0 Auto-traced contour is usually clockwise Autotraced "hole" is usually counter-clockwise "Enlarge Selection" results in counter-clockwise contour */ macro "Check Direction of Contour [3]"{ getSelectionCoordinates(xx, yy); arm = 1; curvature = Array.getVertexAngles(xx, yy, arm); sum= 0; for(jj = 0; jj < curvature.length; jj++) sum += curvature[jj]; sum = round(sum) print("\\Clear"); selectWindow("Log"); print("Sum of vertex angles = ", sum); if(sum == 360) print("Current ROI direction is clockwise"); if(sum == -360) print("Current ROI direction is counter-clockwise"); } //Marks curvature minima (concave, red) and maxima(convex, green) macro "Vertex Angles of a 'Y' shape [4]"{ close("abc"); newImage("abc", "8-bit white", 500, 500, 1); setFont("SansSerif", 400); drawString("Y", 60, 450); run("Gaussian Blur...", "sigma=18"); setAutoThreshold("Default"); doWand(0, 300); resetThreshold; setMinAndMax(180, 250); run("Interpolate", "interval=4 adjust"); getSelectionCoordinates(xx, yy); run("Add Selection..."); arm = 5; curvature = Array.getVertexAngles(xx, yy, arm); edgeMode = 2; //circular tolerance = 20; maxPosArr = Array.findMaxima(curvature, tolerance, edgeMode); minPosArr = Array.findMinima(curvature, tolerance, edgeMode); for(jj = 0; jj < maxPosArr.length; jj++){ x = xx[maxPosArr[jj]]; y = yy[maxPosArr[jj]]; makeOval(x-5, y-5, 10, 10); run("Properties... ", " fill=green"); run("Add Selection..."); } for(jj = 0; jj < minPosArr.length; jj++){ x = xx[minPosArr[jj]]; y = yy[minPosArr[jj]]; makeOval(x-5, y-5, 10, 10); run("Properties... ", " fill=red"); run("Add Selection..."); } run("Select None"); }