3

I want to find the equivalent of the rotate(image, degree) script command to rotate around the x or y axis (I only need 90º rotations). I know I can do it using the tool menu but it would be much faster if I could find a command or a function to do it using a script.

Thank you in advance!

BmyGuest
  • 6,331
  • 1
  • 21
  • 35

2 Answers2

1

Using the Slice command can be confusing at first, so here is a detailed explanation on using the command for a rotation around the X-axis.

This example shows how one would rotate a 3D data clockwise around its X axis (viewing along X) using the Slice3 command.

The Slice3 command specifies a new view onto an existing data array.

  • It first specifies the origin pixel, i.e. the coordinates (in the original data) which will be represented by (0,0,0) in the new view.

  • It then specifes the sampling direction, length and stepsize for each of its new three axes.
    The first triplet specifies how the coordinates (in the original data) change along the new image's x-direction, the second triplet for the new images's y-direction and the last triplet for the new image's z-direction.

So a rotation around the x-axis can be imagined as: Rotation around X

For the "resampled" data:

  • The new (rotated) data has it's origin at the original's data point (0,0,SZ-1).
  • Its X-direction remains the same, i.e. one step in X in the new data, would increment the coordinate triplet in the original's data also by (1,0,0).
    And one goes SX steps with a step-size of 1.
  • Its Y-direction is essentially the negative Z-direction from before, i.e. one step in Y in the new data, would increment the coordinate triplet in the original's data also by (0,0,-1).
    So one goes SZ steps with a step-size of -1.
  • Its Z-direction is essentially the Y-direction from before, i.e. one step in Z in the new data, would increment the coordinate triplet in the original's data by (0,1,0).
    So one goes SY steps with a step-size of 1.

So, for a clockwise rotation around the X-axis, the command is:
img.Slice3( 0,0,SZ-1, 0,SX,1, 2,SZ,-1, 1,SY,1 )

This command will just create a new view onto the same data (i.e. no addtional memory is used.) So to get the rotated image as a new image (with data values aligned as they should be in memory), one would clone this view into a new image usign ImageClone()

In total, the following script shows this as an example:

// Demo of rotating 3D data orthogonally around the X axis
// This is done by resampling the data using the Slice3 command

// Creation of test image with regcognizeable pattern
number SX = 100
number SY = 30
number SZ = 50
image img := RealImage("Test",4, SX,SY,SZ)

// trig. modulated linear increase in X
img =  icol/iwidth* sin( icol/(iwidth-1) * 5 * Pi() ) **2       
// Simple linear increase in Y
img += (irow/iheight) * 2                                   
// Modulation of values in Z 
// (doubling values for index 0,1, 3, 4, 9, 16, 25, 36, 49) 
img *= (SQRT(iplane) == trunc(SQRT(iplane)) ? 2 : 1 )       
img.ShowImage()

// Show captions. Image coordinate system is
// Origin (0,0,0) in top-left-front most pixel
// X axis goes left to right
// Y axis goes top to down
// Z axis goes front to back 
img.ImageSetDimensionCalibration(0,0,1,"orig X",0)
img.ImageSetDimensionCalibration(1,0,1,"orig Y",0)
img.ImageSetDimensionCalibration(2,0,1,"orig Z",0)
img.ImageGetImageDisplay(0).ImageDisplaySetCaptionOn(1)

// Rotation around X axis, clockwise looking along X
// X --> X`  (unchanged)
// Y --> Z'
// Z --> -Y'
// old origin moves to bottom-left-front most 
// This means for "new" sampling:
// Specify sampling starting point:
//   New origin (0,0,0)'  will be value which was at (0,0,SZ-1)
//   Going one step in X' in the new data, will be like going one step in X 
//   Going one step in Y' in the new data, will be like going one step backwards in Z 
//   Going one step in Z' in the new data, will be like going one step in Y
image rotXCW := img.Slice3( 0,0,SZ-1, 0,SX,1, 2,SZ,-1, 1,SY,1 ).ImageClone()
rotXCW.SetName("rotated X, CW")
rotXCW.ShowImage()
rotXCW.ImageGetImageDisplay(0).ImageDisplaySetCaptionOn(1)


The following methods perform 90degree rotations:

// Functions for 90degree rotations of data
image RotateXCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( 0,0,SZ-1, 0,SX,1, 2,SZ,-1, 1,SY,1 ).ImageClone()
}

image RotateXCCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( 0,SY-1,0, 0,SX,1, 2,SZ,1, 1,SY,-1 ).ImageClone()
}

image RotateYCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( SX-1,0,0, 2,SZ,1, 1,SY,1, 0,SX,-1 ).ImageClone()
}

image RotateYCCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( 0,0,SZ-1, 2,SZ,-1, 1,SY,1, 0,SX,1 ).ImageClone()
}

image RotateZCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( 0,SY-1,0, 1,SY,-1, 0,SX,1, 2,SZ,1 ).ImageClone()
}

image RotateZCCW( image input )
{
    number SX,SY,SZ
    input.Get3DSize(SX,SY,SZ)
    return input.Slice3( SX-1,0,0, 1,SY,1, 0,SX,-1, 2,SZ,1 ).ImageClone()
}

Rotations around the z-axis could als be done with RotateRight() and RotateLeft(). Note, however, that these commands will not adapt the images' dimension calibrations, while the Slice3 command will.

BmyGuest
  • 6,331
  • 1
  • 21
  • 35
0

For pure orthogonal rotation the easiest (and fastest) way is to use the'slice' commands, i.e. 'slice3' for 3D images. It turns out that the latest version of GMS has an example of it in the help documention, so I'm just copy-pasting the code here:

number sx = 10
number sy = 10
number sz = 10

number csx, csy, csz 
image img3D := RealImage( "3D", 4, sx, sy, sz )
img3D = 1000 + sin( 2*PI() * iplane/(idepth-1) ) * 100 + icol * 10  + irow
img3D.ShowImage()

// Rotate existing image
if ( OKCancelDialog( "Rotate clockwise (each plane)\n= Rotate block around z-axis" ) )
 img3D.RotateRight()



if ( OKCancelDialog( "Rotate counter-clockwise (each plane)\n= Rotate block around z-axis" ) )
 img3D.RotateLeft()


if ( OKCancelDialog( "Rotate block counter-clockwise around X-axis" ) )
{
 // Equivalent of sampling the data anew
 // x-axis remains 
 // y- and z-axis change their role
 img3D.Get3DSize( csx, csy, csz )        // current size along axes
 img3D = img3D.Slice3( 0,0,0, 0,csx,1, 2,csz,1, 1,csy,1 )
}

if ( OKCancelDialog( "Rotate block clockwise around X-axis" ) )
{
 // Equivalent of sampling the data anew
 // x-axis remains 
 // y- and z-axis change their role
 img3D.Get3DSize( csx, csy, csz )        // current size along axes
 img3D = img3D.Slice3( 0,csy-1,csz-1, 0,csx,1, 2,csz,-1, 1,csy,-1 )
}

if ( OKCancelDialog( "Rotate 30 degree (each plane)\n= Rotate block around z-axis" ) )
{
 number aDeg = 30
 number interpolMeth = 2
 number keepSize = 1
 image rotImg := img3D.Rotate( 2*Pi()/360 * aDeg, interpolMeth, keepSize )
 rotImg.ShowImage()
}

You may also want to look at this answer for some more info on subsampling and creating differnt views on data.

BmyGuest
  • 6,331
  • 1
  • 21
  • 35