Macro programs

Macro programs for measuring root length and diameter is shown. Readers who want to use this macro should get macro programs from here.

Filter files

Filter files for macro programs

For Scion Image(Windows)

Ver 1.80 (new version) is here.

Ver 1.54 (old version)

{ver 1.54          97 Aug22                 (C) 1997 Kimura Kazuhiko  }
{Macro progrom for calculating Total Length or Length&Width   }
{EdgeFilter and EdgeFilter2 should be in the NIH image folder }
{Diagonal count was modified to avoide overestimation due to }
{    false diagonal connections during counting pixels                   }
{Routine for diameter less than 1 unit  is added }
{This is for Scion Image only. Delete4sides was replaced by add4sides. 98 May08}


VAR 
  i,j,width,height,EdgeCount,DiagonalCount,TotalCount,PicN,IterateN,ThresholdValue:integer; 
  Perimeter,TotalLength,BeforeLength,HorPerLength,DiagonalLength,Scale,AspectRatio:real;
  filename,unit : string;

procedure initialize;
begin
  PicN:=PicNumber;
  IterateN:=1;
  GetPicSize(width,height); 
  GetScale(scale,unit,Aspectratio);
  ResetCounter;
  SetCounter(20);
  SetPrecision(2,12);
 {SetOptions('User2 Length Area');}
  SetOptions('User1 User2 Length');
  SetUser1Label('TotalLength');
  SetUser2Label('Width'); 
  BeforeLength:=0; 
  for i:=1 to 20 do
  begin
    rUser1[i]:=0;
    rUser2[i]:=0;
    rLength[i]:=0;
  end;
end;

procedure delete4sides;{set 0 for 4sides}{No more needed for ImagePC}
begin
  for i:=1 to 4095 do LineBuffer[i]:=0;
  PutRow(0,0,width);
  PutRow(0,height-1,width);
{ PutColumn does not work if the column length > 4096}
{ Program was modified as below                       }
  for i:=0 to height-1 do putpixel(0,i,0);
  for i:=0 to height -1 do putpixel(width-1,i,0);
end;

procedure add4sides;{for ImagePC}
begin
  SelectAll;
  Copy;
  SetNewSize(width+2,height+2);
  MakeNewWindow('4 sides added');
  Paste;
end;

procedure NoiseReduction; {remove isolated pixel}
begin
  SetPicName('Removing Isolated Pixels');
  SetBinaryCount(8);
  Erode;
  SetPicName('Isolated Pixels Removed');
  SelectAll;
  Duplicate('EdgeDeleted');{Noise Reduced}
  SetPicName('EdgeDeleted');{added for appending in ImagePC}
end;

procedure SkeletonCalculation;
begin
  SetPicName('Calculating Skeleton Length');  
  Convolve('EdgeFilter2');
  ChangeValues(0,129,0);{delete non skeleton pixels}
  ShowHistogram;Dispose;

  TotalCount:=Histogram[130]+Histogram[135]+Histogram[140]+Histogram[145]+Histogram[150]+Histogram[156]+Histogram[161]+Histogram[166]+Histogram[171]+Histogram[176]+Histogram[182]+Histogram[187]+Histogram[192]+Histogram[197]+Histogram[202]+Histogram[208]+Histogram[213]+Histogram[218]+Histogram[223]+Histogram[228]+Histogram[234]+Histogram[239]+Histogram[244]+Histogram[249]+Histogram[255];

  HorPerLength:=((Histogram[156]+Histogram[161]+Histogram[166]+Histogram[171]+Histogram[176])+2*(Histogram[182]+Histogram[187]+Histogram[192]+Histogram[197]+Histogram[202])+3*(Histogram[208]+Histogram[213]+Histogram[218]+Histogram[223]+Histogram[228])+4*(Histogram[234]+Histogram[239]+Histogram[244]+Histogram[249]+Histogram[255]))/2;   
{
  DiagonalLength:=((Histogram[135]+Histogram[161]+Histogram[187]+Histogram[213]+Histogram[239])+2*(Histogram[140]+Histogram[166]+Histogram[192]+Histogram[218]+Histogram[244])+3*(Histogram[145]+Histogram[171]+Histogram[197]+Histogram[223]+Histogram[249])+4*(Histogram[150]+Histogram[176]+Histogram[202]+Histogram[228]+Histogram[255]))/2;
}

  DiagonalLength:=((Histogram[135]+Histogram[161])+2*(Histogram[140]+Histogram[166])+3*(Histogram[145]+Histogram[171]/3)+4*(Histogram[150]))/2;

  TotalLength:=sqrt(sqr(DiagonalLength)+sqr(DiagonalLength+HorPerLength*0.5))+HorPerLength*0.5;

  {++++++++++  save skeleton , if you want +++++++++++++++++}
{  filename:='skeleton';
  filename:=concat(filename,chr(48+IterateN));
  SetSaveAs('TIFF');
  SaveAs(filename);
}
  {++++++++++  save skeleton +++++++++++++++++++++++++++++}
  {for next }
  SelectWindow('Calculating Skeleton Length*');{ImagePC only to specify the window to be disposed}
  Dispose;{Skeleton}
  ShowMessage(IterateN,'normaly terminated');
  rUser1[IterateN]:=TotalLength/scale*2.54;
  rUser2[IterateN]:=(IterateN-1)*1.78/scale*25.4;
  rLength[IterateN]:=abs(BeforeLength-TotalLength)/scale*2.54;
  rArea[IterateN]:=totalCount/scale*2.54*1.10;{Length by line intercept ,Tanaka's way}
  BeforeLength:=TotalLength;
  ShowResults;
  IterateN:=IterateN+1;
end;{of SkeletonCalculation}

procedure TotalSkeleton;
begin
  SelectWindow('Isolated Pixels Removed*');{* is added for ImagePC}
  SetPicName('Finding Skeleton');
  Skeletonize;
  SetPicName('Skeleton');
  SkeletonCalculation;
end;{of TotalSkeleton}  

procedure EdgeDeletion;
begin
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}
  SetPicName('Deleting Edges');
  Convolve('EdgeFilter');
  ShowHistogram;Dispose;
  TotalCount:=Histogram[255];
  ChangeValues(0,153,0);{delete false dots}
  SetThreshold(254);{delete edge dots}
  MakeBinary;
  SetPicName('EdgeDeleted');
  Duplicate('Peeled/Skeletonizing');
end;{of EdgeDeletion}

procedure PeelAndSkeleton;
begin  {routine for diameter less than 1 unit  is added}
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}
  Duplicate('deleting a line');
  Setbinarycount(5);
  Erode;
  Skeletonize;
  SkeletonCalculation;	
   rUser2[IterateN-1]:=1/scale*25.4;
  repeat 
    EdgeDeletion;
    Skeletonize;
    SetPicName('Deleting Noise');
    SkeletonCalculation;
    rUser2[IterateN-1]:=(IterateN-3)*1.78/scale*25.4;
 until (TotalCount=0);
 rUser2[IterateN-1]:=(IterateN-3)*1.78/scale*25.4;
 rUser2[IterateN]:=0; 
end;{ of PeelAndSkeleton}

Macro 'Length&Width';
begin
  initialize;
 { delete4sides;}{removed because too late in ImagePC}
  Add4sides;{ instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;
  PeelAndSkeleton;
end;

procedure MainProcess;
begin
  initialize;
  {delete4sides;}{removed because too late in ImagePC}
  Add4sides;{ instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;
  PeelAndSkeleton; 
end;

Macro 'TotalLength';
begin
  initialize;
  {delete4sides;}{removed because too late in ImagePC}
  Add4sides; {instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;
end;

Procedure FileProcessForSkeleton;{(FileName,ThresholdValue)};
begin
    open(filename);
    {sharpen;sharpen;}{these process may be changed to get clear image}
    SetThreshold(ThresholdValue);
    MakeBinary;
    MainProcess;
    filename:=concat(filename,'sr154');
    SetExport('Measurements');
    Export(filename);
    disposeAll;
 end;

Macro 'Main';
begin
  {FileName and ThresholdValue should be described below}
                                                                                                                                               
 filename:='mac:LMS-300dpi:LMS111-1a';ThresholdValue:=122;FileProcessForSkeleton;
 filename:='mac:LMS-300dpi:LMS111-2a';ThresholdValue:=122;FileProcessForSkeleton;
 filename:='mac:LMS-300dpi:LMS111-3a';ThresholdValue:=122;FileProcessForSkeleton;
 filename:='mac:LMS-300dpi:LMS111-4a';ThresholdValue:=122;FileProcessForSkeleton;
 filename:='mac:LMS-300dpi:LMS111-5a';ThresholdValue:=122;FileProcessForSkeleton;

end;

Version 1.80

{ver 1.80                 Aug 6,1997 (C) 1997 Kimura Kazuhiko}
{Macro progrom for calculating Total Length or Length&Width   }
{EdgeFilter and EdgeFilter2 should be in the NIH image folder }
{Diagonal count was modified to avoide overestimation due to  }
{false diagonal connections during counting pixels            }
{New diameter estimation was used.                            }
{Surface area calculation is added                               }
{routine for diameter less than 1 unit  is added}
{This is for Scion Image only. Delete4sides was replaced by add4sides. 98 May08}

VAR
i,j,width,height,EdgeCount,DiagonalCount,TotalCount,TotalPixelN,PicN,IterateN,ThresholdValue:integer; 
  Perimeter,TotalLength,BeforeLength,HorPerLength,DiagonalLength,Scale,AspectRatio, SumArea:real;
filename,unit,DFName : string;

procedure initialize;
begin
  PicN:=PicNumber;
  IterateN:=1;
  SumArea:=0;
  GetPicSize(width,height); 
  GetScale(scale,unit,Aspectratio);
  ResetCounter;
  SetCounter(30);
  SetPrecision(3,12);
 {SetOptions('User2 Length Mean');}
  SetOptions('User1 User2 Length Area');
  SetUser1Label('Length#');
  SetUser2Label('Width'); 
  BeforeLength:=0; 
  for i:=1 to 30 do
  begin
    rUser1[i]:=0;
    rUser2[i]:=0;
    rLength[i]:=0;
    rArea[i]:=0;
    rMean[i]:=0;
  end;
end;

procedure delete4sides;{set 0 for 4sides}{No more needed for ImagePC}
begin
  for i:=1 to 4095 do LineBuffer[i]:=0;
  PutRow(0,0,width);
  PutRow(0,height-1,width);
{ PutColumn does not work if the column length > 4096}
{ Program was modified as below                       }
  for i:=0 to height-1 do putpixel(0,i,0);
  for i:=0 to height -1 do putpixel(width-1,i,0);
end;

procedure add4sides;{for ImagePC}
begin
  SelectAll;
  Copy;
  SetNewSize(width+2,height+2);
  MakeNewWindow('4 sides added');
  Paste;
end;

procedure NoiseReduction; {remove isolated pixel}
begin
  SetPicName('Removing Isolated Pixels');
  SetBinaryCount(8);
  Erode;
  SetPicName('Isolated Pixels Removed');
  SelectAll;
  Duplicate('EdgeDeleted');{Noise Reduced}
  SetPicName('EdgeDeleted');{added for appending in ImagePC}
end;

procedure SkeletonCalculation;
begin
  {++++++++++  save skeleton , if you want +++++++++++++++++}
{  filename:='skeleton';
  filename:=concat(filename,J);
  SetSaveAs('TIFF');
  SaveAs(filename);
}
  {++++++++++  save skeleton +++++++++++++++++++++++++++++}
 
  SetPicName('Calculating Skeleton Length');  
  Convolve('EdgeFilter2');
  ChangeValues(0,129,0);{delete non skeleton pixels}
  ShowHistogram;Dispose;

  TotalCount:=Histogram[130]+Histogram[135]+Histogram[140]+Histogram[145]+Histogram[150]+Histogram[156]+Histogram[161]+Histogram[166]+Histogram[171]+Histogram[176]+Histogram[182]+Histogram[187]+Histogram[192]+Histogram[197]+Histogram[202]+Histogram[208]+Histogram[213]+Histogram[218]+Histogram[223]+Histogram[228]+Histogram[234]+Histogram[239]+Histogram[244]+Histogram[249]+Histogram[255];

  HorPerLength:=((Histogram[156]+Histogram[161]+Histogram[166]+Histogram[171]+Histogram[176])+2*(Histogram[182]+Histogram[187]+Histogram[192]+Histogram[197]+Histogram[202])+3*(Histogram[208]+Histogram[213]+Histogram[218]+Histogram[223]+Histogram[228])+4*(Histogram[234]+Histogram[239]+Histogram[244]+Histogram[249]+Histogram[255]))/2;   
{
  DiagonalLength:=((Histogram[135]+Histogram[161]+Histogram[187]+Histogram[213]+Histogram[239])+2*(Histogram[140]+Histogram[166]+Histogram[192]+Histogram[218]+Histogram[244])+3*(Histogram[145]+Histogram[171]+Histogram[197]+Histogram[223]+Histogram[249])+4*(Histogram[150]+Histogram[176]+Histogram[202]+Histogram[228]+Histogram[255]))/2;
}

  DiagonalLength:=((Histogram[135]+Histogram[161])+2*(Histogram[140]+Histogram[166])+3*(Histogram[145]+Histogram[171]/3)+4*(Histogram[150]))/2;

  TotalLength:=sqrt(sqr(DiagonalLength)+sqr(DiagonalLength+HorPerLength*0.5))+HorPerLength*0.5;

 {for next }
  SelectWindow('Calculating Skeleton Length*');{ImagePC only to specify the window to be disposed}
  Dispose;{Skeleton}
  ShowMessage(IterateN,'normaly terminated');
  rUser1[IterateN]:=TotalLength/scale*2.54;
  rLength[IterateN]:=abs(BeforeLength-TotalLength)/scale*2.54;
  rMean[IterateN]:=totalCount/scale*2.54*1.10;{Tanaka's method}
  BeforeLength:=TotalLength;
  ShowResults;
  IterateN:=IterateN+1;
end;{of SkeletonCalculation}

procedure TotalSkeleton;
begin
  SelectWindow('Isolated Pixels Removed*');{* is added for ImagePC}
  ShowHistogram;Dispose;
  TotalPixelN :=histogram[255];
  rArea[IterateN]:=TotalPixelN*3.1415/scale*2.54/scale*2.54; 
  SetPicName('Finding Skeleton');
  Skeletonize;
  SetPicName('Skeleton');
  SkeletonCalculation;
end;{of TotalSkeleton}  

procedure EdgeDeletion;
begin
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}
  SetPicName('Deleting Edges');
  Convolve('EdgeFilter');
  ShowHistogram;Dispose;
  TotalCount:=Histogram[255];
  ChangeValues(0,153,0);{delete false dots}
  SetThreshold(254);{delete edge dots}
  MakeBinary;
  SetPicName('EdgeDeleted');
  Duplicate('Peeled/Skeletonizing');
end;{of EdgeDeletion}

procedure FilterLength;{less than 1unit width}
begin
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}  
  Duplicate('Image B');
  Convolve('DFA-   0.5');
  SetThreshold(185);{deleted if less than 3 of 8-neighbors}
  MakeBinary;
  Imagemath('and',picnumber,picnumber-1,1,0,'Image C');
  SelectWindow('Image A');
  Dispose;
  SelectWindow('Image B');
  Dispose;
  SelectWindow('Image C');
  Duplicate('Image A');
  SelectWindow('Image C');
  Skeletonize;
  SetBinaryCount(8);Erode;
  SkeletonCalculation;
  rUser2[IterateN-1]:=1/scale*25.4;
  rArea[IterateN-1]:=rLength[IterateN-1]*rUser2[IterateN-1]/10*3.1415;
  sumArea:=sumArea+rArea[IterateN-1];
  rArea[IterateN]:=sumArea;{may be overwritten, but last calculation remains as totalArea}
end;

procedure FilterAndLength;
begin
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}  
  Duplicate('Image B');
  DFName:=concat('DFA-',J);
  Convolve(DFName);
  SetThreshold(254);
  MakeBinary;
  Imagemath('and',picnumber,picnumber-1,1,0,'Image C');
  SelectWindow('Image A');
  Dispose;
  SelectWindow('Image B');
  Dispose;
  SelectWindow('Image C');
  Duplicate('Image A');
  SelectWindow('Image C');
  Skeletonize;
  SetBinaryCount(8);Erode;
  SkeletonCalculation;
  rUser2[IterateN-1]:=sqrt(J)*2/scale*25.4;
  rArea[IterateN-1]:=rLength[IterateN-1]*rUser2[IterateN-1]/10*3.1415;
  sumArea:=sumArea+rArea[IterateN-1];
  rArea[IterateN]:=sumArea;{may be overwritten, but last calculation remains as totalArea}
end;

procedure WidthAndLength;
begin
  SelectWindow('EdgeDeleted*');{* is added for ImagePC}  
  Duplicate('Image A');
  if TotalCount >0 then FilterLength;{for less than 1 unit width}; 
  J:=1;if TotalCount >0 then FilterAndLength; if TotalCount=0 then exit;
  J:=2;if TotalCount >0 then FilterAndLength; 
  J:=4;if TotalCount >0 then FilterAndLength; 
  J:=5;if TotalCount >0 then FilterAndLength; 
  J:=8;if TotalCount >0 then FilterAndLength; 
  J:=9;if TotalCount >0 then FilterAndLength; 
  J:=13;if TotalCount >0 then FilterAndLength; 
  J:=16;if TotalCount >0 then FilterAndLength; 
  J:=20;if TotalCount >0 then FilterAndLength; 
  J:=25;if TotalCount >0 then FilterAndLength; 
  J:=32;if TotalCount >0 then FilterAndLength; 
  J:=36;if TotalCount >0 then FilterAndLength; 
  J:=41;if TotalCount >0 then FilterAndLength; 
  J:=49 ;if TotalCount >0 then FilterAndLength; 
  J:=58 ;if TotalCount >0 then FilterAndLength; 
  J:=68 ;if TotalCount >0 then FilterAndLength; 
  J:=80 ;if TotalCount >0 then FilterAndLength; 
  J:=98 ;if TotalCount >0 then FilterAndLength; 
  J:= 117;if TotalCount >0 then FilterAndLength; 
  J:= 137;if TotalCount >0 then FilterAndLength; 
end;{WidthAndLength}

procedure MainProcess;
begin
  initialize;
  {delete4sides;}{removed because too late in ImagePC}
  Add4sides; {instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;
  WidthAndLength;
end;

Macro 'TotalLength';
begin
  initialize;
  {delete4sides;}{removed because too late in ImagePC}
  Add4sides; {instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;

end;

Macro 'Length&Width';
begin
  initialize;
  {delete4sides;}{removed because too late in ImagePC}
  Add4sides; {instead of delete4sides, ImagePC only}
  NoiseReduction;  
  TotalSkeleton;
  WidthAndLength;
end;

Procedure FileProcessForSkeleton;{(FileName,ThresholdValue)};
begin
    open(filename);
    sharpen;{sharpen;}{these process may be changed to get clear image}
    SetThreshold(ThresholdValue);
    MakeBinary;
    MainProcess;
    filename:=concat(filename,'result');
    SetExport('Measurements');
    Export(filename);
    disposeAll;
 end;

Macro 'Main';
begin
  {FileName and ThresholdValue should be described below}
                                                                                                                                             
{ filename:='mac:migaku:sand0-1-2';ThresholdValue:=50;FileProcessForSkeleton;}
 filename:='mac:migaku:sand0-1-3';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-1-4';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-2-1';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-2-2';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-2-3';ThresholdValue:=37;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-2-4';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-2-5';ThresholdValue:=50;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-3-1';ThresholdValue:=60;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-3-2';ThresholdValue:=60;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-3-3';ThresholdValue:=60;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-3-4';ThresholdValue:=60;FileProcessForSkeleton;
 filename:='mac:migaku:sand0-3-5';ThresholdValue:=50;FileProcessForSkeleton;


end;

Copyright 1998-2003, KIMURA Kazuhiko (kimura@bios.tohoku.ac.jp), last updated 2003-1-10