{These macros were designed for measurement of chord length and internal surface area on histologic sections of lungs but could probably be modified for any image with dark lines on light background. The basic macro is A, which measures chord length. It expects to see a series of open images and operates on them sequentially. You need to have made up two grids, one using only vertical lines, one using only horizontal lines, the location of which are put in the appropriate part of "procedure chordlength". (I have enclosed a J. Russ' macro to make up grids.) The macro processes the image, using an interactive threshold setting first, then opens the test grid and subjects the image to a mathematical "and" in order to generate lines equivalent to chord length. The program then averages the length. The other macros calculate the legth of the interface of alveoli to air. They employ a procedure ("onion") which allows Image to see interior holes. They will work on one image at a time rather than on a group of images since Image seems to have an internal buffer overflow problem occasionally and unpredictably using these macros. This is usually overcome by using an inversion of the image, e.g. using macro C rather than B. The absolute size for chord length in pixels per micron is set using the denominator in the calculation in Macro A. Otherwise change the number in the set scale command of the appropriate macro. Contributed by Rob Homer, Robert.Homer@yale.edu} procedure processimage; var g,intval:integer; begin IntVal:=GetNumber('Set Threshold(1--255):',50); for g:=1 to nPics do begin choosePic(g); SetThreshold(IntVal); MakeBinary;Filter('Median');filter('median'); Invert; end; end; procedure invertimage; var r:integer; begin for g:=1 to nPics do begin selectpic(g); Invert; end; end; procedure chordlength; var g,d,e:integer begin for g:=1 to nPics do begin choosepic(g); d:=picnumber; Open('power hd:applications:graphics:NIH Image 1-60:macros:gridxx'); e:=PicNumber; ImageMath('and',d,e,1,0,'result'); AnalyzeParticles('ignore');Dispose; choosePic(e);Dispose; Open('power hd:applications:graphics:NIH Image 1-60:macros:gridyy'); e:=PicNumber; imageMath('and',d,e,1,0,'Result'); AnalyzeParticles('ignore');Dispose; ChoosePic(e); Dispose; end; end; Procedure onion; begin repeat begin z:=PidNumber; Duplicate('copy'); y:=PidNumber; AnalyzeParticles('include'); autothreshold;makebinary; ImageMath('xor',z,y,1,0,z); Choosepic(y);Dispose; choosepic(z); ShowHistogram; s:=histogram[255]; choosepic(z); end; Until (s=0); end; macro 'Chord excluding edges-pic [A]'; var IntVal,g,d,e,i:integer; sum:real; file:string; begin SetPrecision(2,8); SetParticleSize(15,500000); SetOptions('Area'); ResetCounter; SetScale(1,'pixel',1); processimage; chordlength; SetUser1Label('mean'); file:=WindowTitle; sum:=0; for i:=1 to rCount do sum:=sum+rArea[i]; rUser1[rCount]:=sum/(rCount*1.5); UpdateResults; SetExport('measurements'); Export('chord length', file); end; end; macro 'Total surface area-single [E]'; var IntVal,e,z,y,i,s:integer; sum:real; file:string; begin IntVal:=GetNumber('Threshold equals?(1--255):',50); SetPrecision(2,8); file:=WindowTitle; SetParticleSize(50,500000); SetOptions('Perimeter, User1'); ResetCounter; Redirect(false); LabelParticles(false); OutlineParticles(false); IgnoreParticlesTouchingEdge(false); IncludeInteriorHoles(false); WandAutoMeasure(false); AdjustAreas(false); SetUser1Label('total length'); SetScale(1.5,'µm',1); SetThreshold(IntVal); MakeBinary;Filter('Median'); filter('median'); onion; Dispose; dispose; sum:=0; for i:=1 to rCount do sum:=sum+rLength[i]; rUser1[rCount]:=sum; showresults; SetExport('measurements'); Export('perimeter', file); end; macro 'Total surface area-invert-single [F]'; var IntVal,e,z,y,i,s:integer; sum:real; file:string; begin IntVal:=GetNumber('Threshold equals?(1--255):',50); SetPrecision(2,8); file:=WindowTitle; SetParticleSize(50,500000); SetOptions('Perimeter, User1'); ResetCounter; Redirect(false); LabelParticles(false); OutlineParticles(false); IgnoreParticlesTouchingEdge(false); IncludeInteriorHoles(false); WandAutoMeasure(false); AdjustAreas(false); SetUser1Label('total length'); SetScale(1.5,'µm',1); SetThreshold(IntVal); MakeBinary;Filter('Median'); filter('median'); invert; onion; Dispose; dispose; sum:=0; for i:=1 to rCount do sum:=sum+rLength[i]; rUser1[rCount]:=sum; showresults; SetExport('measurements'); Export('perimeter', file); end; macro 'Total surface area-no process-single [B]'; {when used in conjunction with macro A above, need to subtract approximately total perimeter of window.} var IntVal,e,z,y,i,s:integer; sum:real; file:string; begin SetPrecision(2,8); SetParticleSize(50,500000); SetOptions('Perimeter, User1'); ResetCounter; Redirect(false); LabelParticles(false); OutlineParticles(false); IgnoreParticlesTouchingEdge(false); IncludeInteriorHoles(false); WandAutoMeasure(false); AdjustAreas(false); SetUser1Label('total length'); SetScale(1.5,'µm',1); file:=WindowTitle; onion; Dispose; dispose; sum:=0; for i:=1 to rCount do sum:=sum+rLength[i]; rUser1[rCount]:=sum; showresults; SetExport('measurements'); Export('perimeter', file); end; macro 'Total surface area-invert-no process-single [C]'; var IntVal,e,z,y,i,s:integer; sum:real; file:string; begin SetPrecision(2,8); SetParticleSize(50,500000); SetOptions('Perimeter, User1'); ResetCounter; Redirect(false); LabelParticles(false); OutlineParticles(false); IgnoreParticlesTouchingEdge(false); IncludeInteriorHoles(false); WandAutoMeasure(false); AdjustAreas(false); SetUser1Label('total length'); SetScale(1.5,'µm',1); file:=WindowTitle; invert; onion; Dispose; dispose; sum:=0; for i:=1 to rCount do sum:=sum+rLength[i]; rUser1[rCount]:=sum; showresults; SetExport('measurements'); Export('perimeter', file); end; macro 'Draw GridÉ'; var x,y,xinc,yinc,width,height:integer; begin GetPicSize(width,height); xinc:=GetNumber('Horizontal Spacing:',16); yinc:=GetNumber('Vertical Spacing:',xinc); x:=0; y:=0; repeat x:=x+xinc; y:=y+yinc; moveto(0,y); lineto(width,y); moveto(x,0); lineto(x,height); until (x>width) and (y>height); end;