project 3D plot to 2D screen plane - matlab

I have got the following in Matlab (solution as in the example in http://uk.mathworks.com/help/matlab/ref/viewmtx.html):
subplot(211)
h = ezplot3('cos(t)', 'sin(t)', 'sin(5*t)', [-pi pi]);
data = get(h,{'XData','YData','Zdata'});
data = [cat(1,data{:})', ones(numel(data{1}),1)];
% Projection matrix on screen
[az,el] = view(); A = viewmtx(az,el);
data_transformed = A*data';
subplot(212)
plot(data_transformed(1,:), data_transformed(2,:))
That transformation does not work with:
h = ezplot3('t', 'sin(t)', '20*cos(t)', [0 10*pi]);
How to get the screen projection of the 3rd plot?
Also, any links to the math behind the projection, with examples would be nice too :)

The projection depends on view. If you try with various view values, the project in 2D will produce different results.
For example, [az,el]=view(60,30); and you will have this projection.
and [az,el]=view(30,15); you will have this image

It turns out you need to normalize by the DataAspectRatio, so the viewTransform matrix becomes:
[az, el] = view(gca);
A = viewmtx(az,el) * makehgtform('scale',1./get(gca,'DataAspectRatio'));
The full answer can be seen on http://uk.mathworks.com/matlabcentral/answers/248362-screen-2d-projection-of-3d-plot

Related

In Matlab, how to programmatically add datatip to trisurf objects with known vertices index?

Trisurf(f,x,y,z) function can draw a patch object. How can I add datatip to this object at the known vertices index with code?
I tried to use the following codes in 2017b
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf); %h_surf is the handle of trisurf
hdtip.Cursor.Position=pos; %this commond seems cannot find the exact vertex and depends on the view angle, where pos is the vertex coordinates.
hdtip.Cursor.DataIndex=idx; %try to use this command to assign the vertex index, but not successful.DataIndex seems not the vertex index.
Accordint to #Woffie's suggestions, I tuned a little bit to reproduce the error with different view angle in 2017b and 2019b.
First to enable view([180,0]); line. Run the code to get the correct result. And then without closing the figure,comment this line, only remain view([0,0]); to get the wrong result. But if add Close all to the front of the script, should get the correct result each time. (But still don't know the reason, whether it's a bug or not and how to avoid it smartly.)
It might be good to note, in 2D plots, this usually is not a problem since one doesn't usually change the view.
ngrid=1000;%actualy doesnot matter.
x=linspace(-3,3,ngrid+1);
y=linspace(-3,3,ngrid+1);
[x,y] = meshgrid(x,y);
tri = delaunay(x,y);
z = peaks(x,y);
x=(x+3)/6;y=(y+3)/6;
h_surf = trisurf(tri,x,y,z,'EdgeAlpha',0.1);
x0=0.25;y0=0.44;%the above normlization are not necessary but easier to setup the query node.
z0=z(round(y0*ngrid)+1,round(x0*ngrid)+1);
pos=[x0,y0,z0];
view([0,0]);
view([180,0]); %toggle between these two view angles to see the difference.
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf);
hdtip.Cursor.Position = pos;
hdtip.Cursor.Position
BTW, I also figured out how to use hdtip.Cursor.DataIndex=idx. Basically, DataIndex here is the linear index for h_surf.XData(or YData or ZData), while the XData, YData, ZData are mxn matrice as the node/vertex coordinates of all faces in h_surf, where m is the number of nodes in each face and n is the number of the faces. So it will be straightforward to convert to node index into DataIndex.
I'll use the trisurf example from the docs to create a mesh:
[x,y] = meshgrid(1:15,1:15);
tri = delaunay(x,y);
z = peaks(15);
h_surf = trisurf(tri,x,y,z);
Now the tri matrix contains the indices within x, y, and z for each vertex in the mesh. We can choose a vertex index idx, and the corresponding value from each of the x/y/z arrays to use as the .Position property of your data cursor. Contrary to your comment, the Position property does not depend on the view angle, it is the position relative to the axes (and therefore your data).
So
idx = 123; % intex within triangulation "tri"
xcurs = x(tri(idx)); % = 5 in this example
ycurs = y(tri(idx)); % = 6 in this example
zcurs = z(tri(idx)); % = 0.65233 in this example
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf);
hdtip.Cursor.Position = [xcurs,ycurs,zcurs];
You could determine idx however you want, then use a common idx to extract the aligned x, y, and z coordinates.
Two different views to show the data tip stays in place:
This example was run using MATLAB R2017b.

Transform a photo according to a function [MATLAB]

I'm a beginner in matlab and I'm trying to transform a photo according to a function given in the code.
My aim is to see where some points of the R^2 plan go. For example, i'd like to transform :
But I can't figure this out.
I found some good conversations on this topic:
https://www.mathworks.com/matlabcentral/answers/81975-is-it-possible-to-pass-an-image-as-an-input-to-a-function-in-matlab
and good functions like :
https://www.mathworks.com/help/images/ref/imtransform.html
https://www.mathworks.com/help/images/ref/imwarp.html
but I don't understand what to do with that because I don't have a matrix but just like the function "1/z"...
The aim is to do something better than this :
How to plot the Wolfram Alpha grid? [MATLAB]
I've tried to add colors to the mesh graph but I ve not succed in doing so... I could only find how to change uniformly the colors, like setting all in green...
If you have another solution not using an image but constructing a
grid of a range of colors and then deforming it (like in the link) or
even better, instead of a grid, creating a whole plan with an uniform
distribution of the colors... it also fixes the problem!
Thank you !
You can use the surf function to plot a grid with colored patches. If you use the same code in my answer to your previous question, you could visualize the original grid with colors as follows:
C = X.^2 + Y.^2; %change this to any function you like to get different color patterns
surf(X,Y,C);
view([0, 90]); %view the mesh from above
Now, if you want to see how the transformed mesh looks like, you can do:
surf(U,V,C);
view([0, 90]);
where U and V are computed according to my previous answer.
Edit: Added sample code for transforming an image using geometricTransform2d and imwarp.
clear
clc
A = imread('peppers.png');
figure(1)
imshow(A)
t1 = geometricTransform2d(#ftransform);
Rin = imref2d(size(A),[-1 1],[-1 1]);
Rout = imref2d(size(A),[-5 5],[-5 5]);
B = imwarp(A, Rin, t1,'OutputView',Rout);
figure(2);
imshow(B)
function Xt = ftransform(X)
Z = complex(X(:,1),X(:,2));
Zt = 1./Z;
Xt(:,1) = real(Zt);
Xt(:,2) = imag(Zt);
end

how to get camera projection matrix using the matlab?

Thank you for your attention first.
Recently I am trying to use the Matlab program provided by Andrea Fusiello1, Emanuele Trucco2, Alessandro Verri3 in the A compact algorithm for rectification of stereo pairs to rectify the pictures got from the two cameras in my research project about stereo calibration.
Though the Matlab code is not complex, how to get the projection matrixs of the two cameras still confused me.
I used the following Matlab code to get the Internal matrix and R and T of each camera. And I think I can get the projection matrix by using the formula: P = A1*[R|T]. However, as you can see in the picture, the consequence is strange.
So I think there is something wrong with the projection matrixs I got. Could anyone told me how to get the projection matrixs correctly?
matlab code:
numImages = 9;
files = cell(1, numImages);
for i = 1:numImages
files{i} = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', ...
'calibration', 'left', sprintf('left%d.bmp', i));
end
[imagePoints, boardSize] = detectCheckerboardPoints(files);
squareSize = 120;
worldPoints = generateCheckerboardPoints(boardSize, squareSize);
cameraParams = estimateCameraParameters(imagePoints, worldPoints);
imOrig = imread(fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', ...
'calibration', 'left', 'left9.bmp'));
[imagePoints, boardSize] = detectCheckerboardPoints(imOrig);
[R, t] = extrinsics(imagePoints, worldPoints, cameraParams);
The consequence:
There is a built in function cameraMatrix in the Computer Vision System Toolbox to compute the camera projection matrix.
However, if you are trying to do stereo rectification, you should calibrate a stereo pair of cameras using Stereo Camera Calibrator app, and then use rectifyStereoImage function. See this example.
The thing to keep in mind is that the functions in the Computer Vision System Toolbox use the post-multiply convention, i.e. row vector times the matrix. Because of this, the rotation matrices and the camera projection matrix are transposes of their conterparts in Trucco and Veri, and the other textbooks. So the formula used by cameraMatrix is
P = [R;t] * K
So P ends up being 4-by-3, and not 3-by-4. This may explain why you are getting weird results.

Matlab: ring-like graphs

is there a simple way in Matlab to create visualisations like the following?
Important are the 2 ring-like shapes and the attached vectors, (more or less) pointing to the center of the black spots. Hints to other visualisation tools creating vector images which might lead to similar results are also very appreciated! All my efforts to solve that task did not bring me any further...
Matlab would be a good platform for automatically generating this kind of visualisation for different "spot-scenarios"...
Thank you in advance,
M.
Here's part of the figure. The rest should be easy to figure out
%# define the ring
phi = linspace(0,2*pi,360);
innerRim = [cos(phi)',sin(phi)'];
outerRim = [cos(phi)',sin(phi)']*1.3;
xRing = [outerRim(:,1),innerRim(:,1),innerRim([2:end,1],1),outerRim([2:end,1],1)]';
yRing = [outerRim(:,2),innerRim(:,2),innerRim([2:end,1],2),outerRim([2:end,2],2)]';
%# create some data. 0 for black 0.5 for gray.
%# RingData has a value for each degree
ringData = ones(1,360) * 0.5;
ringData(25:30) = 0;
ringData(77:80) = 0;
ringData(240:255) = 0;
%# plot the ring
%# for an outer ring, add 1 to xRing, yRing
figure
patch(xRing,yRing,ringData,'EdgeColor','none');
set(gca,'cLim',[0 1]);
axis square
axis off
set(gcf,'color','w');
%# plot three arrows at the origin
hold on, qh=quiver(zeros(3,1),zeros(3,1),[0.4;0.3;-0.5],[0.7;-0.1;0.3])
set(qh,'LineWidth',3)
You can start with a compass plot: http://www.mathworks.com/help/techdoc/ref/compass.html or a polar plot: http://www.mathworks.com/help/techdoc/ref/polar.html . Another option is: http://undocumentedmatlab.com/blog/jfreechart-graphs-and-gauges/ .

How can I implement a fisheye lens effect (barrel transformation) in MATLAB?

How can one implement the fisheye lens effect illustrated in that image:
One can use Google's logo for a try:
BTW, what's the term for it?
I believe this is typically referred to as either a "fisheye lens" effect or a "barrel transformation". Here are two links to demos that I found:
Sample code for how you can apply fisheye distortions to images using the 'custom' option for the function maketform from the Image Processing Toolbox.
An image processing demo which performs a barrel transformation using the function tformarray.
Example
In this example, I started with the function radial.m from the first link above and modified the way it relates points between the input and output spaces to create a nice circular image. The new function fisheye_inverse is given below, and it should be placed in a folder on your MATLAB path so you can use it later in this example:
function U = fisheye_inverse(X, T)
imageSize = T.tdata(1:2);
exponent = T.tdata(3);
origin = (imageSize+1)./2;
scale = imageSize./2;
x = (X(:, 1)-origin(1))/scale(1);
y = (X(:, 2)-origin(2))/scale(2);
R = sqrt(x.^2+y.^2);
theta = atan2(y, x);
cornerScale = min(abs(1./sin(theta)), abs(1./cos(theta)));
cornerScale(R < 1) = 1;
R = cornerScale.*R.^exponent;
x = scale(1).*R.*cos(theta)+origin(1);
y = scale(2).*R.*sin(theta)+origin(2);
U = [x y];
end
The fisheye distortion looks best when applied to square images, so you will want to make your images square by either cropping them or padding them with some color. Since the transformation of the image will not look right for indexed images, you will also want to convert any indexed images to RGB images using ind2rgb. Grayscale or binary images will also work fine. Here's how to do this for your sample Google logo:
[X, map] = imread('logo1w.png'); % Read the indexed image
rgbImage = ind2rgb(X, map); % Convert to an RGB image
[r, c, d] = size(rgbImage); % Get the image dimensions
nPad = (c-r)/2; % The number of padding rows
rgbImage = cat(1, ones(nPad, c, 3), rgbImage, ones(nPad, c, 3)); % Pad with white
Now we can create the transform with maketform and apply it with imtransform (or imwarp as recommended in newer versions):
options = [c c 3]; % An array containing the columns, rows, and exponent
tf = maketform('custom', 2, 2, [], ... % Make the transformation structure
#fisheye_inverse, options);
newImage = imtransform(rgbImage, tf); % Transform the image
imshow(newImage); % Display the image
And here's the image you should see:
You can adjust the degree of distortion by changing the third value in the options array, which is the exponential power used in the radial deformation of the image points.
I think you are referring to the fisheye lens effect. Here is some code for imitating fisheye in matlab.
Just for the record:
This effect is a type of radial distortion called "barrel distortion".
For more information please see:
http: //en.wikipedia.org/wiki/Distortion_(optics)
Here is a different method to apply an effect similar to barrel distortion using texture mapping (adapted from MATLAB Documentation):
[I,map] = imread('logo.gif');
[h,w] = size(I);
sphere;
hS = findobj('Type','surface');
hemisphere = [ones(h,w),I,ones(h,w)];
set(hS,'CData',flipud(hemisphere),...
'FaceColor','texturemap',...
'EdgeColor','none')
colormap(map)
colordef black
axis equal
grid off
set(gca,'xtick',[],'ztick',[],'ytick',[],'box','on')
view([90 0])
This will give you the circular frame you are looking for but the aliasing artifacts might be too much to deal with.