Moving point along a curve (3D-Animation plots) - matlab

I am trying to make an animation of the trajectory (circular orbit of 7000 km altitude) of a satellite orbiting the Earth. The following vectors x,y,z represents the coordinates of it (obtained integrating the acceleration due to the nonspherical gravitational potential) in the reference system.
fh = figure('DoubleBuffer','on');
ah = axes('Parent',fh,'Units','normalized','Position',[0 0 1 1],...
'DataAspectRatio',[1 1 1],'DrawMode','fast');
x = 1.0e+003 * [ 1.293687086462776 1.355010603320554 ...
1.416226136451621 1.477328806662750 1.538313743926646...
1.841302933101510 2.140623861743577 2.435680048370655...
2.725883985836056 3.830393161542639 4.812047393962632...
5.639553477924236 6.285935904692739 6.778445814703028...
6.981534839226300 6.886918327688911 6.496619397538814...
5.886899070860056 5.061708852126299 4.051251943168882...
2.891621923700204 1.551975259009857 0.148687346809817...
-1.259946709379085 -2.614876359324573 -3.789635985368149...
-4.822735075152957 -5.675398819678173 -6.314344260262741...
-6.725008970265510 -6.860046738669579 -6.714044347581475...
-6.291232549137548 -5.646225528669501 -4.790489239458692...
-3.756316068441812 -2.581710448683235 -1.257064527234605...
0.118190083177733 1.488198207705392 2.797262268588749...
3.943218990855596 4.943060241667732 5.760107224604901...
6.363435161221018 6.741208871652011 6.844507242544970...
6.669637491855506 6.222229021788314 5.549112743364572...
4.665587166679964 3.605338508383659 2.407805301565781...
1.076891826523990 -0.297413079432155 -1.658804233546807...
-2.950960371016551 -4.105336427038419 -5.093651475630134...
-5.875676956725480 -6.417825276834068 -6.694317613708315...
-6.702354075060146 -6.441476385534835 -5.920328191821120...
-5.149356931765655 -4.165756794143557 -3.010476122311884...
-1.730623521107957 -0.547981318845428 0.651933236927557...
1.830754553013015 2.950797411065132];
y = 1.0e+003 *[ -6.879416537989226 -6.867600717396513...
-6.855237614338527 -6.842328214064634 -6.828873545169439...
-6.753459997528374 -6.664593892931937 -6.562452270514113...
-6.447238135027323 -5.857768973060929 -5.080802144227667...
-4.141502963266585 -3.069449548231363 -1.712593819793112...
-0.283073212084787 1.157789207734001 2.547934226666446...
3.733185664633135 4.781256997101091 5.653507474532885...
6.316540958291930 6.760480121739906 6.924451844039825...
6.801366712306432 6.393950562012035 5.763652137956600...
4.918852380803697 3.890903548710424 2.717191733101876...
1.385839187748386 -0.001786735280855 -1.388680800030854...
-2.717513794724399 -3.877348086956174 -4.892062889940518...
-5.723943344458780 -6.341064412332522 -6.729295147896739...
-6.844976271597333 -6.684181367561298 -6.252308741323985...
-5.600523241569850 -4.741636145151388 -3.707934368103928...
-2.537101251915556 -1.208445066639178 0.169057351189467...
1.539102816836380 2.845512534980855 3.993289528709769...
4.989150886098799 5.795183343929699 6.379362665363127...
6.723976759736427 6.794165677259719 6.586864956951024...
6.108394444576384 5.387403581100790 4.449452017586583...
3.332306147336086 2.080126804848620 0.757432563194591...
-0.595089763589023 -1.923045482863719 -3.172486599444496...
-4.302442851663575 -5.254127434062967 -5.988250483410006...
-6.472859710456819 -6.675113607083117 -6.664054266658221...
-6.440275312105615 -6.010308893159839];
z = [ -1.348762314964606 -1.416465504571016 -1.484053975854905...
-1.551522350691171 -1.618865254528658 -1.953510294130345...
-2.284215283426580 -2.610320163346533 -2.931177500785390...
-4.153679292291825 -5.242464339076090 -6.162825517200489...
-6.884797354552217 -7.440577139596716 -7.680358197465111...
-7.594616346122523 -7.183952381870657 -6.529293328494871...
-5.637062917332294 -4.540678277777376 -3.279180600545935...
-1.817413221203883 -0.280548741687378 1.268253040429052...
2.764251377698321 4.066975661566477 5.218214283582148...
6.174673504642019 6.899157495671121 7.375688520371054...
7.548875108319217 7.410793523141250 6.965068314483629...
6.271309946313485 5.343254095742233 4.215431448848456...
2.928028129903598 1.469574073877195 -0.048649548535536...
-1.563638474934283 -3.013536101911645 -4.285161526803897...
-5.397128342069014 -6.308837263463213 -6.985946890567337...
-7.415475222950275 -7.542406523585701 -7.363021555333582...
-6.884639818710263 -6.158276823110702 -5.199186592259776...
-4.043958234344444 -2.736923814690622 -1.283388986878655...
0.219908617803070 1.712828428793243 3.135072606759898...
4.411790351254605 5.510842969067953 6.387336537361380...
7.004133661144990 7.332163450286972 7.366696289243980...
7.105258174916579 6.555393588532904 5.727091807637045...
4.660073989309112 3.399622357708514 1.999243120787114...
0.701744421660999 -0.620073499615723 -1.923270654698332...
-3.164705887374677 ];
load('topo.mat','topo','topomap1');
[x1,y1,z1] = sphere(50);
x1 = 6678.14*x1;
y1 = 6678.14*y1;
z1 = 6678.14*z1;
props.AmbientStrength = 0.1;
props.DiffuseStrength = 1;
props.SpecularColorReflectance = .5;
props.SpecularExponent = 20;
props.SpecularStrength = 1;
props.FaceColor= 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
props.Cdata = topo;
surface(x1,y1,z1,props);
light('position',[-1 0 1]);
light('position',[-1.5 0.5 -0.5], 'color', [.6 .2 .2]);
view(3);
handles.p1 = line('parent',ah,'XData',x(1),'YData',y(1),'ZData',...
z(1),'Color','red','LineWidth',2);
handles.p2 = line('parent',ah,'XData',x(end),'YData',y(end),...
'ZData',z(end),'Marker','o','MarkerSize',6,'MarkerFaceColor','b');
oaxes([0 0 0],'Arrow','extend','AxisLabelLocation','side',...
'Xcolor','green','Ycolor','green','Zcolor','green');
axis vis3d equal;
handles.XLim = get(gca,'XLim');
handles.YLim = get(gca,'YLim');
handles.ZLim = get(gca,'ZLim');
set([handles.p1,handles.p2],'Visible','off');
xmin = handles.XLim(1);
ymin = handles.YLim(1);
zmin = handles.ZLim(1);
xmax = handles.XLim(2);
ymax = handles.YLim(2);
zmax = handles.ZLim(2);
set(ah, 'XLim', [xmin xmax],'YLim', [ymin ymax],'Zlim',[zmin zmax]);
view(3);
handles.hsat = line('parent',ah,'XData',x(1), 'YData',y(1),...
'ZData',z(1),'Marker','o', 'MarkerSize',6,'MarkerFaceColor','b');
k = uint8(2);
u2 = uint8(length(x));
while k<u2
handles.htray(k) = line([x(k-1) x(k)],[y(k-1) y(k)],[z(k-1) z(k)],...
'Color','red','LineWidth',3);
set(handles.hsat,'XData',x(k),'YData',y(k),'ZData',z(k));
drawnow;
k = k + 1;
end
where oaxes is a FEX application that allows getting an axes located (in this case) at the origin (0,0,0) of the PlotBox.
I have read the User Guide's Graphics section in the Matlab Help Browser. It recommends to use low-level functions for speeding the graphics output (this is the reason for which I use the line function instead of plot3) and the renderer painters for line graphics. In my case, I can not use it because I have a surface (the Earth) which is not well drawn by it. I want to get something similar to this (I have tried to get in touch with the author but I have not got response). The final result is a slow (it takes 11.4 seconds in my computer with microprocessor intel core i5) and discontinuous animation (perhaps I need more points to get the blue point's movement looks like continuous but the integrator's output points are invariable). I would like to know what I should make to improve it. Thank you for your attention. Cheers.

A couple of things here.
DrawMode=fast probably doesn't do what you think it does. It's turning off depthsorting. I think that you really want depthsorting here.
You're creating line objects in the inner loop. You really want create a small number of graphics objects and reuse them. Could you create a single line object and set the XData, YData, & ZData, in the loop?
You can use hgtransform to avoid modifying the coordinates of hsat (as described here), but that would only make a difference if hsat was much more complex. I don't think it would buy you anything in this case.
You could reduce the resolution of your surface.
You probably want to set the figure's Renderer property to OpenGL.
In this case, but I'm getting almost 20 frames per second on my system with your code. After making those changes, I'm getting about 100 frames per second. What sort of framerate are you shooting for here?

I believe the main reason your animation is slow is because you are using the Phong lighting algorithm which is computationally expensive. To see the effect it has on performance, try specifying Gouraud shading instead:
%#lighting('gouraud');
props.FaceLighting = 'gouraud'; %# faster interpolating method

Related

How to convert from the image coordinates to Cartesian coordinates

I have this 3D image generated from the simple code below.
% Input Image size
imageSizeY = 200;
imageSizeX = 120;
imageSizeZ = 100;
%# create coordinates
[rowsInImage, columnsInImage, pagesInImage] = meshgrid(1:imageSizeY, 1:imageSizeX, 1:imageSizeZ);
%# get coordinate array of vertices
vertexCoords = [rowsInImage(:), columnsInImage(:), pagesInImage(:)];
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
radius = 28;
%# calculate distance from center of the cube
sphereVoxels = (rowsInImage - centerY).^2 + (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2;
%# Now, display it using an isosurface and a patch
fv = isosurface(sphereVoxels,0);
patch(fv,'FaceColor',[0 0 .7],'EdgeColor',[0 0 1]); title('Binary volume of a sphere');
view(45,45);
axis equal;
grid on;
xlabel('x-axis [pixels]'); ylabel('y-axis [pixels]'); zlabel('z-axis [pixels]')
I have tried plotting the image with isosurface and some other volume visualization tools, but there remains quite a few surprises for me from the plots.
The code has been written to conform to the image coordinate system (eg. see: vertexCoords) which is a left-handed coordinate system I presume. Nonetheless, the image is displayed in the Cartesian (right-handed) coordinate system. I have tried to see this displayed as the figure below, but that’s simply not happening.
I am wondering if the visualization functions have been written to display the image the way they do.
Image coordinate system:
Going forward, there are other aspects of the code I am to write for example if I have an input image sphereVoxels as in above, in addition to visualizing it, I would want to find north, south east, west, top and bottom locations in the image, as well as number and count the coordinates of the vertices, plus more.
I foresee this would likely become confusing for me if I don’t stick to one coordinate system, and considering that the visualization tools predominantly use the right-hand coordinate system, I would want to stick with that from the onset. However, I really do not know how to go about this.
Right-hand coordinate system:
Any suggestions to get through this?
When you call meshgrid, the dimensions x and y axes are switched (contrary to ndgrid). For example, in your case, it means that rowsInImage is a [120x100x200] = [x,y,z] array and not a [100x120x200] = [y,x,z] array even if meshgrid was called with arguments in the y,x,z order. I would change those two lines to be in the classical x,y,z order :
[columnsInImage, rowsInImage, pagesInImage] = meshgrid(1:imageSizeX, 1:imageSizeY, 1:imageSizeZ);
vertexCoords = [columnsInImage(:), rowsInImage(:), pagesInImage(:)];

Lighting Stays with Animated Surface in Matlab

I'm attempting to animate a rotating sphere in Matlab, however the lighting on the sphere rotates with it. I instead want the sphere to rotate while the lighting remains fixed with the coordinate system. Here's a gif of what my code is currently producing: Animation. And here is my code:
% Simulation Time
dt = 0.05;
time = 0:dt:5;
% Prep Figure
figure('Color',[1 1 1],'Renderer','zbuffer','ColorMap', [1,0,0; 0,0,1])
% Generate Sphere
[X,Y,Z] = sphere(20);
r = 0.75*25.4;
h = surf(r*X,r*Y,r*Z,Z,'FaceColor','interp');
hold on
% Adjust Axes, Lighting, and Shading
axis equal
view([40 25]);
light('Position',[1 1 1])
set(findobj(gca,'type','surface'),...
'FaceLighting','phong',...
'AmbientStrength',.3,'DiffuseStrength',.8,...
'SpecularStrength',.9,'SpecularExponent',25,...
'BackFaceLighting','unlit','EdgeColor','k')
filename = 'Rotation.gif';
for n = 1:36
rotate(h,[0 0 1],10,[0 0 0])
im = frame2im(getframe(1));
[imind,cm] = rgb2ind(im,256);
if n == 1;
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',dt);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',dt);
end
end
As already mentioned in the comments:
Seems like it might be an issue with the surface VertexNormals not
updating.
The solution was to download the rotate.m function fixed File Exchange submission.
The description:
Bug evidence:
[x,y,z] = sphere(20);
hs=surf(x,y,z,'facecolor','y');
view(2)
axis equal
hl=light;
lightangle(hl,0,0)
% light is on -Y axis, thus at the
% bottom
rotate(hs,[0 0 1],30)
% rotate sphere to the right from 30°
It looks like the light has moved. This is due to a bug in rotate.m
function. The "VertexNormals" property of the surf object is not
updated as "xdata", "ydata" and "zdata" properties are.
This is fixed in the submitted version of rotate.m.

Transform Image using Roll-Pitch-Yaw angles (Image rectification)

I am working on an application where I need to rectify an image taken from a mobile camera platform. The platform measures roll, pitch and yaw angles, and I want to make it look like the image is taken from directly above, by some sort of transform from this information.
In other words, I want a perfect square lying flat on the ground, photographed from afar with some camera orientation, to be transformed, so that the square is perfectly symmetrical afterwards.
I have been trying to do this through OpenCV(C++) and Matlab, but I seem to be missing something fundamental about how this is done.
In Matlab, I have tried the following:
%% Transform perspective
img = imread('my_favourite_image.jpg');
R = R_z(yaw_angle)*R_y(pitch_angle)*R_x(roll_angle);
tform = projective2d(R);
outputImage = imwarp(img,tform);
figure(1), imshow(outputImage);
Where R_z/y/x are the standard rotational matrices (implemented with degrees).
For some yaw-rotation, it all works just fine:
R = R_z(10)*R_y(0)*R_x(0);
Which gives the result:
If I try to rotate the image by the same amount about the X- or Y- axes, I get results like this:
R = R_z(10)*R_y(0)*R_x(10);
However, if I rotate by 10 degrees, divided by some huge number, it starts to look OK. But then again, this is a result that has no research value what so ever:
R = R_z(10)*R_y(0)*R_x(10/1000);
Can someone please help me understand why rotating about the X- or Y-axes makes the transformation go wild? Is there any way of solving this without dividing by some random number and other magic tricks? Is this maybe something that can be solved using Euler parameters of some sort? Any help will be highly appreciated!
Update: Full setup and measurements
For completeness, the full test code and initial image has been added, as well as the platforms Euler angles:
Code:
%% Transform perspective
function [] = main()
img = imread('some_image.jpg');
R = R_z(0)*R_y(0)*R_x(10);
tform = projective2d(R);
outputImage = imwarp(img,tform);
figure(1), imshow(outputImage);
end
%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
R = [cosd(psi) -sind(psi) 0;
sind(psi) cosd(psi) 0;
0 0 1];
end
%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
R = [cosd(theta) 0 sind(theta);
0 1 0 ;
-sind(theta) 0 cosd(theta) ];
end
%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
R = [1 0 0;
0 cosd(phi) -sind(phi);
0 sind(phi) cosd(phi)];
end
The initial image:
Camera platform measurements in the BODY coordinate frame:
Roll: -10
Pitch: -30
Yaw: 166 (angular deviation from north)
From what I understand the Yaw-angle is not directly relevant to the transformation. I might, however, be wrong about this.
Additional info:
I would like specify that the environment in which the setup will be used contains no lines (oceanic photo) that can reliably used as a reference (the horizon will usually not be in the picture). Also the square in the initial image is merely used as a measure to see if the transformation is correct, and will not be there in a real scenario.
So, this is what I ended up doing: I figured that unless you are actually dealing with 3D images, rectifying the perspective of a photo is a 2D operation. With this in mind, I replaced the z-axis values of the transformation matrix with zeros and ones, and applied a 2D Affine transformation to the image.
Rotation of the initial image (see initial post) with measured Roll = -10 and Pitch = -30 was done in the following manner:
R_rotation = R_y(-60)*R_x(10);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ]
This implies a rotation of the camera platform to a virtual camera orientation where the camera is placed above the scene, pointing straight downwards. Note the values used for roll and pitch in the matrix above.
Additionally, if rotating the image so that is aligned with the platform heading, a rotation about the z-axis might be added, giving:
R_rotation = R_y(-60)*R_x(10)*R_z(some_heading);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ]
Note that this does not change the actual image - it only rotates it.
As a result, the initial image rotated about the Y- and X-axes looks like:
The full code for doing this transformation, as displayed above, was:
% Load image
img = imread('initial_image.jpg');
% Full rotation matrix. Z-axis included, but not used.
R_rot = R_y(-60)*R_x(10)*R_z(0);
% Strip the values related to the Z-axis from R_rot
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ];
% Generate transformation matrix, and warp (matlab syntax)
tform = affine2d(R_2d);
outputImage = imwarp(img,tform);
% Display image
figure(1), imshow(outputImage);
%*** Rotation Matrix Functions ***%
%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
R = [cosd(psi) -sind(psi) 0;
sind(psi) cosd(psi) 0;
0 0 1];
end
%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
R = [cosd(theta) 0 sind(theta);
0 1 0 ;
-sind(theta) 0 cosd(theta) ];
end
%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
R = [1 0 0;
0 cosd(phi) -sind(phi);
0 sind(phi) cosd(phi)];
end
Thank you for the support, I hope this helps someone!
I think you can derive transformation this way:
1) Let you have four 3d-points A(-1,-1,0), B(1,-1,0), C(1,1,0) and D(-1,1,0). You can take any 4 noncollinear points. They not related to image.
2) You have transformation matrix, so you can set your camera by multiplying points coords by transformation matrix. And you'll get 3d coords relative to camera position/direction.
3) You need to get projection of your points to screen plane. The simpliest way is to use ortographic projection (simply ignore depth coordinate). On this stage you've got 2D projections of transformed points.
4) Once you have 2 sets of 2D points coordinates (the set from step 1 without 3-rd coordinate and the set from step 3), you can compute homography matrix in standard way.
5) Apply inverse homograhy transformation to your image.
You need to estimate a homography. For an off-the-shelf Matlab solution, see function vgg_H_from_x_lin.m from http://www.robots.ox.ac.uk/~vgg/hzbook/code/ .
For the theory dig into a Computer Vision textbook, such as the one available freely at http://szeliski.org/Book/ or in Chapter 3 of http://programmingcomputervision.com/downloads/ProgrammingComputerVision_CCdraft.pdf
Maybe my answer is not correct due to my mis-understanding of the camera parameters, but I was wondering whether the Yaw/Pitch/Roll is relative to the position of your object. I used the formula of general rotations, and my code is below (the rotation functions R_x, R_y, and R_z were copied from yours, I didn't paste them here)
close all
file='http://i.stack.imgur.com/m5e01.jpg'; % original image
I=imread(file);
R_rot = R_x(-10)*R_y(-30)*R_z(166);
R_rot = inv(R_rot);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ];
T = maketform('affine',R_2d);
transformedI = imtransform(I,T);
figure, imshow(I), figure, imshow(transformedI)
The result:
This indicates that you still need some rotation operation to get the 'correct' alignment in your mind (but probably not necessary the correct position in the camera's mind).
So I change R_rot = inv(R_rot); to R_rot = inv(R_rot)*R_x(-5)*R_y(25)*R_z(180);, and now it gave me:
Looks better like what you want.
Thanks.

Calculate heading angle from x and y information

I have data that records the x and y positions of an animal in a 2D assay over time stored in a matlab matrix. I can plot these co-ordinates over time, and extract the velocity information and plot this using cline.
The problem I am having at the moment is calculating the heading angle. It should be a trivial trigonometry question, but I am drawing a blank on the best way to start.
The data is stored in a matrix xy representing x and y co-ordinates:
796.995391705069 151.755760368664
794.490825688073 150.036697247706
788.098591549296 145.854460093897
786.617021276596 144.327659574468
781.125000000000 140.093750000000
779.297872340426 138.072340425532
775.294642857143 133.879464285714
What I would like to be able to do is know the angle of the line drawn from (796.995, 151.755) to (794.490, 150.036), and so on. My research suggests atan2 will be the appropriate function, but I am unsure how to call it correctly to give useful information.
difx = xy(1,1) - xy(2,1);
dify = xy(1,2) - xy(2,2);
angle = atan2(dify,difx);
angle = angle*180/pi % convert to degrees
The result is 34.4646. Is this correct?
If it is correct, how do I get the value to be in the range 0-360?
You can use the diff function to get all the differences at once:
dxy = diff(xy); % will contain [xy(2,1)-xy(1,1) xy(2,2)-xy(1,2); ...
Then you compute the angle using the atan2 function:
a = atan2(dxy(:,2), dxy(:,1));
You convert to degrees with
aDeg = 180 * a / pi;
And finally take the angle modulo 360 to get it between 0 and 360:
aDeg = mod(aDeg, 360);
So - you pretty much got it right, yes. Except that you have calculated the heading from point 2 to point 1, and I suspect you want to start at 1 and move towards 2. That would give you a negative number - or modulo 360, an angle of about 325 degrees.
Also, using the diff function gets you the entire array of headings all at once which is a slight improvement over your code.
[rc mi]=
EDIT the problem of "phase wrapping" - when the heading goes from 359 to 0 - is quite a common problem. If you are interested in knowing when a large change happens, you can try the following trick (using aDeg from above - angle in degrees).
dDeg1 = diff(aDeg); % the change in angle
dDeg2 = diff(mod(aDeg + 90, 360)); % we moved the phase wrap point by 180 degrees
dDeg12 = [dDeg1(:) dDeg2(:)]';
[rc mi]= min(abs(dDeg12));
indx = sub2ind(size(dDeg12), mi, 1:size(dDeg12, 2));
result = dDeg12(ii);
What I did there: one of the variables (dDeg or dDeg2) does not see the phase wrap, and the min function finds out which one (it will have a smaller absolute difference). The sub2ind looks up that number (it is either positive or negative - but it's the smaller one of the two), and that is the value that ends up in result.
You can verify the angle by plotting a little line that starts at the first point and end in the direction of the heading. If the angle is correct, it will point in the direction of the next point in xy. Everything depends on where yo define 0 degrees at (straight up, say) from and whether positive degrees is rotation counterclockwise (I do) or clockwise. In MATLAB you can get the numbers between 0 and 360 but using modulo---or you can just add 180 to your results but this will change the definition of where the 0 degree mark is.
I made the following script that is a bit complex but shows how to calculate the heading/angle for all points in vector format and then displays them.
xy =[ 796.995391705069 151.755760368664
794.490825688073 150.036697247706
788.098591549296 145.854460093897
786.617021276596 144.327659574468
781.125000000000 140.093750000000
779.297872340426 138.072340425532
775.294642857143 133.879464285714];
% t = linspace(0,3/2*pi, 14)';
% xy = [sin(t), cos(t)];
% calculate the angle:
myDiff = diff(xy);
myAngle = mod(atan2(myDiff(:,1), myDiff(:,2))*180/pi, 360);
% Plot the original Data:
figure(1);
clf;
subplot(1,3,1);
plot(xy(:,1), xy(:,2), '-bx', 'markersize', 12);
hold all
axis equal;grid on;
title('Original Data');
% Plot the calculated angle:
subplot(1,3,2);
plot(myAngle);
axis tight; grid on;
title('Heading');
% Now plot the result with little lines pointing int he heading:
subplot(1,3,3);
plot(xy(:,1), xy(:,2), '-bx', 'markersize', 12);
hold all
% Just for visualization:
vectorLength = max(.8, norm(xy(1,:)- xy(2,:)));
for ind = 1:length(xy)-1
startPoint = xy(ind,:)';
endPoint = startPoint + vectorLength*[sind(myAngle(ind)); cosd(myAngle(ind))];
myLine = [startPoint, endPoint];
plot(myLine(1,:), myLine(2, :), ':r ', 'linewidth', 2)
end
axis equal;grid on;
title('Original Data with Heading Drawn On');
For example, if you use my test data
t = linspace(0,3/2*pi, 14)';
xy = [sin(t), cos(t)];
You get the following:
and if you do yours you get
Note how the little red line starts at the original data point and moves in the direction of the next point---just like the original blue line connecting the points.
Also note that the use of diff in the code to difference all the points properly at once. This is faster and avoids any problems with the direction--looks like in your case it's swapped.

OpenCV MATLAB: How to draw a line having a particular Intensity profile?

Below is an arbitrary hand-drawn Intensity profile of a line in an image:
The task is to draw the line. The profile can be approximated to an arc of a circle or ellipse.
This I am doing for camera calibration. Since I do not have the actual industrial camera, I am trying to simulate the correction needed for calibration.
The question can be rephrased as I want pixel values which will follow a plot similar to the above. I want to do this using program (Preferably using opencv) and not manually enter these values because I have thousands of pixels in the line.
An algorithm/pseudo code will suffice. Also please note that I do not have any actual Intensity profile, otherwise I would have read those values.
When will you encounter such situation ?
Suppose you take a picture (assuming complete white) from a Camera, your object being placed on table, and camera just above it in vertical direction. The light coming on the center of the picture vertically downward from the camera will be stronger in intensity as compared to the light reflecting at the edges. You measure pixel values across any line in the Image, you will find intensity curve like shown above. Since I dont have camera for the time being, I want to emulate this situation. How to achieve this?
This is not exactly image processing, rather image generation... but anyways.
Since you want an arc, we still need three points on that arc, lets take the first, middle and last point (key characteristics in my opinion):
N = 100; % number of pixels
x1 = 1;
x2 = floor(N/2);
x3 = N;
y1 = 242;
y2 = 255;
y3 = 242;
and now draw a circle arc that contains these points.
This problem is already discussed here for matlab: http://www.mathworks.nl/matlabcentral/newsreader/view_thread/297070
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
h21 = x21^2+y21^2; h31 = x31^2+y31^2;
d = 2*(x21*y31-x31*y21);
a = x1+(h21*y31-h31*y21)/d; % circle center x
b = y1-(h21*x31-h31*x21)/d; % circle center y
r = sqrt(h21*h31*((x3-x2)^2+(y3-y2)^2))/abs(d); % circle radius
If you assume the middle value is always larger (and thus it's the upper part of the circle you'll have to plot), you can draw this with:
x = x1:x3;
y = b+sqrt(r^2-(x-a).^ 2);
plot(x,y);
you can adjust the visible window with
xlim([1 N]);
ylim([200 260]);
which gives me the following result: