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!
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:
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.
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.
I have a surface Z on a X-Y grid for which I want to find the intersection point with a line. I used so far this code for finding the intersection:
x_ray = x_source + t * x_dir
y_ray = y_source + t * y_dir
z_ray = z_source + t * z_dir
height_above_plane = #(t) z_source + t * z_dir - interp2(X, Y, Z, ...
x_source + t*x_dir, y_source + t*y_dir)
t_intercept = fzero(height_above_plane, 0);
my problem is that when my surface is "wiggly", the function has several zero crossing points, and I want to find the minimal out of them.
How can I do that?
Thanks
A possible approach is to project the ray onto the XY domain and draw the corresponding Bresenham line. As you go along this line, grid cell per grid cell, you will compute the Z altitudes along the ray and check if their range overlaps the range of altitudes of the surface (i.e. the min and max value in this cell).
If yes, you have to find the 3D intersection between the ray and the interpolating surface, an hyperbolic paraboloid. If the intersection does fall inside the grid cell considered, you are done. Otherwise, continue the march along the ray.
Convert the surface to matlab mesh, then use this code.
Is there any way to constraint the the imline to be always perpendicular to the other imline drawn on the same object. for ex. I draw a first line using "imline" now I want to draw second line across the first line to be perpendicular to it. if there is a way to force the second imline to be perpendicular to the first line keeping the flexibility of extending the length it will solve my problem some extent.
I want something like a flexible cross hair(which can rotate along the axis and have flexible sides) on my image to measure the height and width of the certain object.
Code:
function perpline()
imshow(rand(200),[]);
line1 = imline(gca,[50 50; 150 150]);
setColor(line1,'r');
line2 = imline(gca,[50 150; 150 50]);
setColor(line2,'g');
addNewPositionCallback(line2,#(pos)callback_line(pos));
function callback_line(pos)
% Must update line1 based on line2's position
pos_line1 = getPosition(line1);
pos_line2 = getPosition(line2);
% Get middle
pos_center = [(pos_line2(1,1)+pos_line2(2,1))/2 (pos_line2(1,2)+pos_line2(2,2))/2];
% Find displacement
vec_disp = [pos_line2(2,1)-pos_line2(1,1) pos_line2(2,2)-pos_line2(1,2)];
% Get normal unit vector
vec_perp = [-vec_disp(2) vec_disp(1)]/norm(vec_disp);
% Preserve length of line2
length_line1 = norm([pos_line1(2,1)-pos_line1(1,1) pos_line1(2,2)-pos_line1(1,2)]);
pos_line1_update = [-vec_perp*length_line1/2+pos_center;
vec_perp*length_line1/2+pos_center];
% Set position
setPosition(line1,pos_line1_update);
end
end
Save it as a function then call it. You can drag the green line around and the red line remains perpendicular. Note that you have to define how you want it to preserve the perpendicularity. I chose to preserve the length of the red line and keep it in the center of the green line.