Hello NIH Imagers, Below is part of a project I've been working on developing tools to quantify the spaces inside the inner ear. You may recall my request a while back for help analyzing a coiled object. Well, using NIH Image and its handy macro language I was able to make a very useful analysis tool. One thing I required to get started was a way to slice a stack in an arbitrary plane. Below is a utility that does this. It's a little crude on grayscale images due to the simple pixel interpolation that's used but was more than adaquate on the binary volumes I segment from the original MRI datasets. Feel free to play with this sometime and comment on any improvements that might come to mind. Most of what's in the macro could go into User.p for increased speed but for debugging I found your macro interface very useful. Some notes: (1) Alpha is the angle which the slicing plane projects through the volume. For example, if alpha is 0 degrees then the slicing plane lies parallel to the slices of the stack. If it is 90 degrees then the slicing plane is orthogonal to the slices. (2) Theta is the angle by which the slicing plane is rotated around the Z axis. I'm sure there are better ways to explain this but if you play with this I think it will become clear. (3) The size of the slicing plane is adjusted by changing the value of the variable Size in the beginning of the Test macro. Thanks again for all your help on this! Sincerely, Art Keating. ************** Pascal part for User.p ******************* unit User; {This module is a good place to put user additions to Image. You will need } {to uncomment the call to InitUser in Image.p.} interface uses QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, Filters, Analysis; procedure InitUser; procedure DoUserCommand1; procedure DoUserCommand2; procedure DoUserMenuEvent (MenuItem: integer); procedure OldUserMacroCode (CodeNumber: integer; Param1, Param2, Param3: extended); procedure UserMacroCode (str: str255; Param1, Param2, Param3: extended); implementation {User global variables go here.} procedure InitUser; begin UserMenuH := GetMenu(UserMenu); InsertMenu(UserMenuH, 0); DrawMenuBar; {Additional user initialization code goes here.} end; procedure GetVector; var i, LineLength: integer; x, y, xinc, yinc, angle: extended; x1, y1, x2, y2, ulength, clength: real; begin with info^, info^.StackInfo^ do begin angle := LAngle; GetLengthOrPerimeter(ulength, clength); LineLength := trunc(ulength); GetLoi(x1, y1, x2, y2); angle := ( angle / 180.0 ) * pi; xinc := cos(angle); yinc := -sin(angle); x := x1; y := y1; for i := 0 to LineLength - 1 do begin MacrosP^.aline[i] := round(GetInterpolatedPixel(x, y)); x := x + xinc; y := y + yinc; end; end; end; procedure ShowNoCodeMessage; begin PutMessage('Requires user written Think Pascal routine. '); end; procedure DoUserCommand1; begin ShowNoCodeMessage end; procedure DoUserCommand2; begin ShowNoCodeMessage end; procedure DoUserMenuEvent (MenuItem: integer); begin case MenuItem of 1: DoUserCommand1; 2: DoUserCommand2; end; end; procedure OldUserMacroCode (CodeNumber: integer; Param1, Param2, Param3: extended); {Obsolete version kept for backward compatibilty.} begin case CodeNumber of 1: ShowNoCodeMessage; 2: ShowNoCodeMessage; 3: ShowNoCodeMessage; 4: ShowNoCodeMessage; otherwise ShowNoCodeMessage; end; end; procedure UserMacroCode (str: str255; Param1, Param2, Param3: extended); begin MakeLowerCase(str); if pos('vector', str) <> 0 then begin GetVector; exit(UserMacroCode); end; ShowNoCodeMessage; end; end. ****************** NIH Image Macro Part ****************** Var deltax,deltay,deltaz,theta,alpha,Size,Dist,pi,pi2: real; DataStack,Slice : Integer; x1,x2,x3,x4,y1,y2,y3,y4,z1,z3: integer; 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; procedure GetUserInfo; var temp : real; begin temp:=(theta/pi)*180; temp := GetNumber(' Slicing Inclination (theta,0 - 180¡):', temp); theta:=(temp/180)*pi; temp:=(alpha/pi)*180; temp := GetNumber('Slicing Plane Angle (alpha,0 - 180¡):', temp); alpha:=(temp/180)*pi; end; procedure FindStop; begin { Find lower Stop Corner} { Find lower boundary point in plane of P1} deltaX := -((cos(theta) * Size)/2); deltay := (sin(theta) * Size)/2; x2 := round(x1+ deltax); y2 := round(y1 + deltay); { Find deltaz} deltaz := (sin(alpha) * Size)/2; z3 := Round(z1 + deltaz); { Find Dist} Dist := (cos(alpha) * Size)/2; { Find Corner x3,y3} deltax := cos(pi2-theta) * Dist; deltay := sin(pi2-theta) * Dist; x3 := round(x2-deltax); y3 := round(y2-deltay); end; procedure GetLines ; var temp1,temp2 : real; i : integer; begin { Iterate through lines of slicing plane till done} i := Size; SetNewSize(Size,Size); MakeNewWindow('Temp'); Slice := PicNumber; repeat deltaz := sin(alpha) * i; ChoosePic(DataStack); temp1 := round(z3-deltaz); if (temp1 <1) then temp1 := 1; if (temp1 > nSlices) then temp1 := nSlices; ChooseSlice(temp1); Dist := cos(alpha) * i; deltax := cos(pi2-theta) * Dist; deltay := sin(pi2-theta) * Dist; x2 := round(x3+deltax); y2 := round(y3+deltay); temp1 := cos(theta) * (Size+1); temp2 := sin(theta) * (Size+1); x4 := round(x2 + temp1); y4 := round(y2 - temp2); MakeLineRoi(x2,y2,x4,y4); usercode('vector',0,0,0); ChoosePic(Slice); PutColumn(i-1,0,Size); i := i -1; until (i = 0); SetForegroundColor(0); MoveTo(Size-1,0); LineTo(Size-1,Size-1); end; procedure FindCenter; begin FindStop; deltaz := sin(alpha) * (XCenter+1); Dist := cos(alpha) * (XCenter+1); deltax := sin(theta) * Dist; deltay := cos(theta) * Dist; x1 := round(x3+deltax+(cos(theta) * YCenter)); y1 := round(y3+deltay-(sin(theta) * YCenter)); z1 := z3-deltaz; end; macro 'SliceOblique [S]'; var i,width:integer; temp : real; begin CheckForStack; DataStack := PicNumber; pi := 3.141592654; pi2 := 1.570796327; Size := 150; theta := .785398163 ; alpha := 1.57079633 ; GetLine(x1,y1,x2,y2,width); if (x1<0) then begin PutMessage('Please make a single point line selection.'); exit; end; z1 := SliceNumber; GetUserInfo; FindStop; GetLines; SelectPic(DataStack); SelectSlice(z1); MakeLineRoi(x1,y1,x1,y1); end;