/* * Macro is written in ImageJ Macro Language (IJ1 Macro, .ijm) * Input for macro is a folder containing two color masks of all samples for measuring. * Lumen masks are optional if Center of Mass should be calculated based on lumen's center of mass (organs with irregular or small lumen). * * ER - 2022. * */ Dialog.create("Average thickness macro"); Dialog.addMessage("Average thickness macro",15); Dialog.addDirectory("Input directory", ""); Dialog.addDirectory("Lumen masks(for CoM)", ""); Dialog.addMessage("Lumen mask files have to be named same as samples with appended L \nExample: Sample.tif should have lumen mask SampleL.tif"); Dialog.addCheckbox("Use scale?", false); Dialog.addNumber("Distance in pixels", ""); Dialog.addNumber("Known distance", ""); Dialog.addString("Unit", ""); Dialog.addMessage("\n"); Dialog.addCheckbox("Is background dark?", false); Dialog.addCheckbox("Use CoM masks?", false); Dialog.addMessage("Measurements start at 3 o’clock position with clockwise increasing angle(1-360)\nAccepts only .tif files!"); Dialog.show(); input = Dialog.getString(); lumen = Dialog.getString(); fileList = getFileList(input); useScale = Dialog.getCheckbox(); scalePix = Dialog.getNumber(); scaleDist = Dialog.getNumber(); scaleUnit = Dialog.getString(); backg = Dialog.getCheckbox(); usecom = Dialog.getCheckbox(); requires( "1.52e" ); me = "Polar_Transformer.class"; emptyArr = newArray(0); setOption("ExpandableArrays", true); images = newArray; avgT = newArray; minT = newArray; maxT = newArray; if ( !File.exists( getDirectory( "plugins" ) + me ) ) exit( "Macro requires PlugIn \"" + nme + "\" !" ); if(useScale == true) unit = "in "+ scaleUnit; else unit = "in pixels"; // main body for ( img = 0; img < lengthOf(fileList); img++ ) { if(endsWith(fileList[img], ".tif")){ // check if file is an image open( input + fileList[img] ); run("Set Scale...", "distance=0 known=0 unit=pixel"); // remove pre-existing scale (needed for polar transformation) imgName = substring(fileList[img], 0, lengthOf(fileList[img])-4); images[img] = imgName; measure(); if (useScale == true) { nRows = Table.size; scaleK = scalePix/scaleDist; for (i = 0; i < nRows; i++) { calc = Table.get(imgName, i) / scaleK; Table.set(imgName, i, calc); } Table.update; } close("*"); } } wait(100); Table.save(input + "\\_RawResults.csv"); // save raw measurment data // calculate average, min, max for (i = 0; i < lengthOf(images); i++) { col = Table.getColumn(images[i]); temp = 0; mi = 0; mx = 0; ag = 0; Array.getStatistics(col, mi, mx, ag, temp); minT[i] = mi; maxT[i] = mx; avgT[i] = ag; } Table.reset("Results"); Table.setColumn("Image /"+unit, images); Table.setColumn("Average", avgT); Table.setColumn("Maximum", maxT); Table.setColumn("Minimum", minT); Table.save(input + "\\_Results.csv"); // save summary table exit("Job done!"); // end of main body function measure () { run( "8-bit" ); if (backg == 1) setAutoThreshold( "Default dark" ); else setAutoThreshold( "Default white" ); run( "Convert to Mask" ); if (usecom == 0) { // use CoM calculated from input image doWand( 0, getHeight() * 0.5 ); List.setMeasurements; x = List.getValue( "XM" ); y = List.getValue( "YM" ); run( "Select None" ); } else { // use lumen masks for CoM open( lumen + imgName + "L.tif" ); run("Set Scale...", "distance=0 known=0 unit=pixel"); run( "8-bit" ); if (backg == 1) setAutoThreshold( "Default dark" ); else setAutoThreshold( "Default white" ); run( "Convert to Mask" ); doWand( 0, getHeight() * 0.5 ); List.setMeasurements; x = List.getValue( "XM" ); y = List.getValue( "YM" ); run( "Select None" ); close(imgName + "L.tif"); } setBatchMode( true ); run( "Polar Transformer", "method=Polar degrees=360 number=360 center_x=[x] center_y=[y]" ); run( "Make Binary" ); for ( i=0; i<360; i++ ) { // measure each row of pixels w = calcWidth( i ); setResult( "Angle /"+unit, i, i ); setResult( imgName, i, w ); } setBatchMode( false ); close(); } function calcWidth( idx ) { // get sum of black pixels from profile plot makeRectangle( 0, idx, getWidth(), 1 ); p = getProfile(); s = 0; for ( i=0; i