{This file contains macros that work with stacks.} procedure CheckForStack; begin if nPics=0 then begin PutMessage('This macro requires a stack.'); exit; end; if nSlices=0 then begin PutMessage('This window is not a stack.'); exit end; end; macro 'Add Slice [A]'; begin CheckForStack; AddSlice end; macro 'Delete Slice [D]'; begin CheckForStack; DeleteSlice end; macro 'First Slice [F]'; begin CheckForStack; SelectSlice(1) end; macro 'Last Slice [L]'; begin CheckForStack; SelectSlice(nSlices) end; macro 'Select SliceÉ [S]'; var n:integer; begin CheckForStack; n:=GetNumber('Slice Number:',trunc(nSlices/2)); SelectSlice(n) end; macro '(-' begin end; macro 'Smooth'; var i:integer; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); SetOption; Smooth; end; end; macro 'Sharpen'; var i:integer; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); SetOption; Smooth; SetOption; Sharpen; end; end; macro 'Reduce Noise'; var i:integer; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); ReduceNoise; end; end; macro 'Apply LUT'; var i,stack,slices:integer; begin CheckForStack; stack:=PicNumber; slices:=nSlices; Duplicate('Temp'); for i:= 1 to slices do begin SelectPic(stack); SelectSlice(i); ApplyLut; SelectPic(nPics); if i<>slices then PropagateLut; end; SelectPic(nPics); Dispose; end; macro 'Fix Colors'; { Changes 0 to 1 and 255 to 254 in all slices. We want to do this because pixel values of 0(which always displays as white) and 255(always displays as black) cause problems when pseudo-coloring images. } var i:integer; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); ChangeValues(0,0,1); ChangeValues(255,255,254); end; end; macro 'Subtract BackgroundÉ'; var radius,i:integer; begin CheckForStack; radius:=GetNumber('Rolling ball radius (pixels):',50); for i:= 1 to nSlices do begin SelectSlice(i); SubtractBackground('2D Rolling Ball',radius); end; end; macro '(-' begin end; procedure CheckForSelection; var x1,y1,x2,y2,LineWidth:integer; begin GetRoi(RoiLeft,RoiTop,RoiWidth,RoiHeight); GetLine(x1,y1,x2,y2,LineWidth); if (RoiWidth=0) or (x1>=0) then begin PutMessage('Please make a rectangular selection.'); exit; end; end; procedure CropAndScale(fast:boolean; angle:real); var i,OldStack,NewStack:integer; RoiLeft,RoiTop,RoiWidth,RoiHeight:integer; N,NewWidth:integer; ScaleFactor:real; OneToOne:boolean; begin CheckForStack; CheckForSelection; SaveState; OldStack:=PicNumber; N:=nSlices; ScaleFactor:=GetNumber('Scale factor(0.05..25):',1.0); OneToOne:=ScaleFactor=1.0; NewWidth:=round(RoiWidth*ScaleFactor); if odd(NewWidth) then begin NewWidth:=NewWidth-1; ScaleFactor:=NewWidth/RoiWidth; end; SetNewSize(RoiWidth*ScaleFactor,RoiHeight*ScaleFactor); MakeNewStack('Stack'); NewStack:=PicNumber; if not OneToOne then begin if fast then SetScaling('Nearest; Create New Window') else SetScaling('Bilinear; Create New Window'); end; SelectPic(OldStack); for i:= 1 to N do begin SelectSlice(1); if OneToOne and (angle=0.0) then Duplicate('Temp') else ScaleAndRotate(ScaleFactor,ScaleFactor,angle); SelectAll; Copy; SelectPic(NewStack); if i<>1 then AddSlice; Paste; SelectPic(nPics); Dispose; {Temp} SelectPic(OldStack); DeleteSlice; end; Dispose; {OldStack} RestoreState; end; macro 'Crop and Scale-FastÉ'; begin CropAndScale(true, 0); end; macro 'Crop and Scale-SmoothÉ'; begin CropAndScale(false, 0); end; procedure Rotate(left:boolean); var i,OldStack,NewStack:integer; RoiLeft,RoiTop,RoiWidth,RoiHeight:integer; N,NewWidth:integer; ScaleFactor,SliceSpacing:real; OneToOne:boolean; begin CheckForStack; SelectAll; GetRoi(RoiLeft,RoiTop,RoiWidth,RoiHeight); OldStack:=PicNumber; SliceSpacing:=GetSliceSpacing; N:=nSlices; SetNewSize(RoiHeight,RoiWidth); MakeNewStack('Stack'); if SliceSpacing>0 then SetSliceSpacing(SliceSpacing); NewStack:=PicNumber; SelectPic(OldStack); for i:= 1 to N do begin SelectSlice(1); if left then RotateLeft(true) else RotateRight(true); SelectAll; Copy; SelectPic(NewStack); if i<>1 then AddSlice; Paste; ChoosePic(nPics); Dispose; SelectPic(OldStack); DeleteSlice; end; Dispose; end; macro 'Rotate Left'; begin rotate(true) end; macro 'Rotate Right'; begin rotate(false) end; macro 'RotateÉ'; var angle:real; begin angle:=GetNumber('Angle(-180.0¡..180.0¡):',45.0); CropAndScale(false, angle); end; macro 'Invert'; var i:integer; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); Invert; end; end; procedure flip(vertical:boolean); var i:integer; SliceSpacing:real; begin CheckForStack; for i:= 1 to nSlices do begin SelectSlice(i); if vertical then FlipVertical else FlipHorizontal; end; end; macro 'Flip Vertical'; begin flip(true) end; macro 'Flip Horizontal'; begin flip(false) end; macro 'Delete Even Slices'; var n:integer; begin CheckForStack; SelectSlice(2); repeat DeleteSlice; n:=SliceNumber; n:=n+2; if n>nSlices then exit; SelectSlice(n); until false; end; macro 'Replicate SlicesÉ'; var n,i,RepFactor:integer; begin CheckForStack; RepFactor:=GetNumber('Replication factor(2,3,4,5,etc):',2); n:=nSlices; repeat SelectSlice(n); SelectAll; Copy; for i:=2 to RepFactor do begin AddSlice; Paste; end; n:=n-1; until n=0; KillRoi; end; macro 'Merge Two Stacks'; { Combines two stacks(w1xh1xd1 and w2xh2xd2) to create a new w1+w2 x max(h1,h2) x max(d1,d2) stack. For example, a 256x256x40 and a 256x256x30 stack would be combined into one 512x256x40 stack. } var i,w1,w2,w3,h1,h2,h3,d1,d2,d3:integer; begin SaveState; if nPics<>2 then begin PutMessage('This macro operates on exactly two stacks.'); exit; end; SelectPic(1); GetPicSize(w1,h1); d1:=nSlices; SelectPic(2); GetPicSize(w2,h2); d2:=nSlices; if d1>=d2 then d3:=d1 else d3:=d2; if d3=0 then begin PutMessage('Both images must be stacks.'); exit; end; w3:=w1+w2; if h1>=h2 then h3:=h1 else h3:=h2; SetNewSize(w3,h3); MakeNewStack('Merged'); for i:=1 to d3 do begin SelectPic(1); SelectSlice(1); SelectAll; Copy; DeleteSlice; SelectPic(3); MakeRoi(0,0,w1,h1); Paste; SelectPic(2); SelectSlice(1); SelectAll; Copy; DeleteSlice; SelectPic(3); MakeRoi(w1,0,w2,h2); Paste; if i2 then begin PutMessage('This macro operates on exactly two stacks.'); exit; end; SelectPic(1); KillRoi; GetPicSize(w1,h1); d1:=nSlices; SelectPic(2); KillRoi; GetPicSize(w2,h2); d2:=nSlices; if d1>=d2 then d3:=d1 else d3:=d2; if (w1<>w2) or (h1<>h2) or (d1<>d2) or (d1=0) then begin PutMessage('This macro requires two stacks that are the same size.'); exit; end; SetNewSize(w1,h1); MakeNewStack('Average'); avg:=PicNumber; for i:=1 to d1 do begin SelectPic(1); SelectSlice(i); SelectPic(2); SelectSlice(i); ImageMath('Add', 1, 2, 0.5, 0, 'Temp'); SelectAll; Copy; dispose; SelectPic(avg); if i<>1 then AddSlice; paste; end; RestoreState; end; macro '(-' begin end; macro 'Save Slices as filesÉ'; { This macro saves the slices in a stack as individual TIFF or PICT files using names of the form needed by Apple's Convert to [QuickTime]Movie utility. To specify the file type, checked either TIFF or PICT in the SaveAs dialog box, which should only appear once. } var i,stack:integer; begin CheckForStack; stack:=PidNumber; for i:= 1 to nSlices do begin SelectPic(stack); SelectSlice(i); Duplicate('Frame.',i:3); SaveAs; {Export;} Dispose; end; end; macro 'Windows to Stack'; {Unlike the menu command of the same name, the windows do not} {all need to be the same size.} var i,width,height,MinWidth,MinHeight,n,stack:integer; isStack:boolean; begin if nPics<=1 then begin PutMessage('At least two images must be open.'); exit; end; MinWidth:=9999; MinHeight:=9999; isStack:=false; for i:=1 to nPics do begin SelectPic(i); GetPicSize(width,height); if width0); end; if isStack then begin PutMessage('This macro does not work with stacks.'); exit; end; if odd(MinWidth) then MinWidth:=MinWidth-1; n:=nPics; SaveState; SetNewSize(MinWidth,MinHeight); MakeNewStack('Stack'); stack:=nPics; for i:=1 to n do begin SelectPic(1); MakeRoi(0,0,MinWidth,MinHeight); copy; Dispose; SelectPic(nPics); paste; if i<>n then AddSlice; end; KillRoi; RestoreState; end; Macro 'Stack to Windows' var mystack,i:integer width,height:integer; begin SaveState; CheckForStack; GetPicSize(width,height); SetNewSize(width,height); mystack := picnumber; for i:=1 to nslices do begin SelectSlice(i); SelectAll; copy; MakeNewWindow(i); paste; SelectPic(myStack); end; KillRoi; RestoreState; end; macro 'Make Cone'; var i,size,margin,MaxRadius,r,r2,center,RodLength,color:integer; begin size:=64; margin:=5; color:=100; SaveState; SetBackgroundColor(255); {Black} SetNewSize(size,size); MakeNewStack('Cone'); for i:=1 to margin do AddSlice; MaxRadius:=(size-2*margin)/2; center:=size div 2; RodLength:=size-2*margin-1; for i:=1 to RodLength do begin AddSlice; r:=MaxRadius*(i/RodLength); MakeOvalRoi(center-r,center-r,r*2,r*2); SetForegroundColor(color); Fill; if (i>RodLength/2) and (i<(RodLength-margin)) then begin r2:=MaxRadius/6; MakeOvalRoi(center-2.125*r2,center-1.3*r2,r2*2,r2*2); SetForegroundColor(color-25); Fill; MakeOvalRoi(center+0.625*r2,center-0.7*r2,r2*2,r2*2); SetForegroundColor(color+25); Fill; end; end; for i:=1 to margin do AddSlice; KillRoi; RestoreState; end; procedure DoReslicing(horizontal:boolean); var stack1,stack2,width,height:integer; RoiLeft,RoiTop,RoiWidth,RoiHeight,max:integer; InputSpacing,OutputSpacing,loc:real; FirstTime:boolean; begin RequiresVersion(1.45); CheckForStack; CheckForSelection; SaveState; SetBackground(0); SetBackground(255); stack1:=PicNumber; InputSpacing:=GetSliceSpacing; if InputSpacing<=0 then InputSpacing:=1; InputSpacing:=GetNumber('Input Slice Spacing(Pixels):',InputSpacing); SetSliceSpacing(InputSpacing); OutputSpacing:=InputSpacing; OutputSpacing:=GetNumber('Output Slice Spacing (Pixels):', OutputSpacing); FirstTime:=true; GetRoi(RoiLeft,RoiTop,RoiWidth,RoiHeight); if horizontal then begin loc:=RoiTop+OutputSpacing; max:=RoiTop+RoiHeight; end else begin loc:=RoiLeft+OutputSpacing; max:=RoiLeft+RoiWidth; end; while locfirst then AddSlice; n:=n+1; Paste; end; end; macro 'Sagitals to CoronalsÉ'; begin ResliceSignaMRI(false,true) end; macro 'Sagitals to AxialsÉ'; begin ResliceSignaMRI(true,true) end; macro 'Coronals to SagitalsÉ'; begin ResliceSignaMRI(false,true) end;