Perspective projection of a 3D model to a 2D plane - matlab

I'm trying to project a 3D model to a 2D plane and I found I should use the projection equation C*((R*X)+T) to do so. C, which is the camera calibration matrix is calculated as follows:
C =[f 0 px;
0 f py;
0 0 1];
First, I want to ask about the focal length f used in the camera calibration matrix. Should I use it with the value in pixels or mm? If in mm how can I get it?
Second I don't really know what the px and py variables stand for I got some information about the data I'm working on bye the exifread function in MATLAB and these are the information I got:
Sharpness: 0
Contrast: 0
SceneCaptureType: 0
FocalLengthIn35mmFilm: 27
DigitalZoomRatio: 1
WhiteBalance: 0
ExposureMode: 0
SceneType: 1
FileSource: 3
SensingMethod: 2
PixelYDimension: 3000
PixelXDimension: 4000
ColorSpace: 1
FlashpixVersion: '0100'
FocalLength: 4.9000
Flash: 1
LightSource: 0
MeteringMode: 4
MaxApertureValue: 3.6150
ExposureBiasValue: 0
ApertureValue: 3.6150
ShutterSpeedValue: 2.3220
CompressedBitsPerPixel: 2.8149
ComponentsConfiguration: [1 2 3 0]
DateTimeDigitized: '2011:06:26 16:55:08'
DateTimeOriginal: '2011:06:26 16:55:08'
ExifVersion: '0221'
ISOSpeedRatings: 100
ExposureProgram: 2
FNumber: 3.5000
ExposureTime: 0.2000
Copyright: 'Copyright 2010'
YCbCrPositioning: 2
DateTime: '2011:06:26 16:55:08'
Software: ' 0.8913'
ResolutionUnit: 2
YResolution: 96
XResolution: 96
Orientation: 1
Model: 'SAMSUNG ES30/VLUU ES30'
Make: 'SAMSUNG'
Thumbnail: [1x1 struct]
Do px and py refer to any of them?

px and py are the coordinates of the principal point. On an ideal camera that would be the center of the image, so you can use width/2, height/2 for a start. For actual values you should use a calibration algorithm.
f should be in pixels.

Related

MATLAB pcolor/surf bilinear interpolation (shading interp)

Consider the following MATLAB code:
C = [ 0 0 0 0 0
0 1 2 1 0
0 2 4 2 0
0 1 2 1 0
0 0 0 0 0 ];
pcolor( C );
shading interp;
axis square
Note that C is invariant under 90 degree rotations. Also note this sentence from the help for pcolor:
With shading interp, each cell is colored by bilinear interpolation of the colors at its four vertices, using all elements of C.
However, the plotted image is as follows:
Note that the image is not invariant under 90 degree rotations (consider e.g. the four corners). Now, unless I horribly misunderstand bilinear interpolation, this must be wrong. MATLAB seems to be interpolating on triangles, which is not the same as bilinear interpolation.
Is there any way of working round this MATLAB bug, and getting correct bilinear interpolation? (Other than manually interpolating additional points myself, which still would not cure the issue if one zoomed in far enough.)
I remember having read a few threads concerning this weird behavior in the official Matlab forums, in the past. Unfortunately, I found none right now with a quick search. Anyway... you aren't the first used pointing out that shading interp, used in combination with with pcolor, behaves in a weird manner, creating shapes that don't reflect the underlying data.
The main problem is that shading interp interpolates between data points without caring about how sensible your grid is to smoothing. If you want a result that doesn't look jagged, you have to provide data sampled at a higher resolution:
C = [
0 0 0 0 0
0 1 2 1 0
0 2 4 2 0
0 1 2 1 0
0 0 0 0 0
];
C = interp2(C,5,'cubic');
pcolor(C);
shading interp;
axis square;
This produces an amazing result, and the output doesn't show any artifact or asymmetry:

Matlab cdfplof do not show complete graph when multiple cdfs are plotted in one graph with x-axis as log scale

I am trying to use cdfplot() to plot multiple sets of data in one graph. When I use the normal x-axis, everything is fine. However, when I try to change the x-axis to log scale, the cdf plot of some sets of data do not display complete.
I have two sets of data: setFive and setSeven. I want to plot cdf of them in the same graph, with x-axis being log scale.
Here are the two graphs, one is in normal x-axis, the other is in log scale x-axis. The cdf of "five" in log scale x-axis does not go to 0.
The two sets of data are:
setSeven=[ 0.1478
0.2493
0.0650
0.1808
0.3633
0.1684
0.3116
0.1398
0
0
0.3069
0.3252
0.1762
0.4192
0
0.1163
0
0
0.2338
0
0.1388
0
0.2420
0.1115
0
0
0
0.1530
0.1675
0.3333
0
0
0.2351
0.1555
0
0
0.1691
0.2042
0.3143
0
0
0.2206
0
0.2288
0.1271
0
0.1852
0
0
0
0.1226
0
0
0.1571
0.1807
0
0
0
0.3231
0.1358
0.1681
0
0.1924
0.1494
0.1474
0.1030
0.2008
0.1455
0
0.2351
0.2537
0
0.1353
0
0.1320
0.1675
0.1844
0
0
0.2691
0.3640
0
0
0
0
0
0.2395
0
0
0
0.3156
0.2007
0.4463
0
0
0.2526
0.2375
0.3521
0.2279
0];
setFive=[0.1476
0.3300
0.0940
0.2704
0.3659
0.2214
0.3658
0.1402
0.2295
0.2105
0.3324
0.4011
0.2823
0.5740
0.2916
0.1940
0.2559
0
0.2423
0.1734
0.1992
0
0.2822
0.4122
0.2312
0
0.2598
0.3808
0.5833
0.6131
0
0.2831
0.6418
0.2269
0.2532
0.1944
0.3515
0.2734
0.3908
0.3223
0
0.3303
0
0.2759
0.2144
0
0
0
0.1747
0.2721
0.2509
0.2542
0
0.1381
0.2562
0.1918
0.2243
0.2260
0.3823
0.2404
0.3963
0.2917
0.2390
0.2818
0.2863
0.2366
0.2289
0
0.1183
0.2660
0.2535
0.1917
0.1976
0
0
0
0
0.4433
0
0.3395
0.4199
0.3674
0
0
0.2814
0
0.3816
0.4754
0.3198
0.4995
0.5585
0.2965
0.5316
0.4914
0.6343
0.4036
0.3632
0.4205
0.3089
0.4521];
Here are the codes:
e=cdfplot(setFive);
set(e,'LineStyle','-','color','k');
hold on;
g=cdfplot(setSeven);
set(g,'LineStyle','--','color','k');
hold on;
set(gca,'Xscale','log');
axis([0 1 0 1]);
get(gca,'xlim')
The problem is due to the processing the function cdfplot makes on the input, coupled with the logarithmic representation.
Consider the setSeven input data set (the same applies to setFive): the first 5 points generated by cdfplot are:
x7= -Inf 0 0 0.0650 0.0650
y7= 0 0 0.4300 0.4300 0.4400
You canget these points using the get function wiht the handles returned by cdfplot:
x5=get(e,'xdata');
y5=get(e,'ydata');
x7=get(g,'xdata');
y7=get(g,'ydata');
where:
x5: x data from setFive data set
y5: y data from setFive data set
x7: x data from setSeven data set
x7: y data from setSeven data set
In the first of your graph, you see the line starting from x=0, y=0 then climbing to x=0, y=0.43.
In this graph actually the first point x=-inf, y=0 is missing since the plot function simply ignores values such as -inf, inf, NaN.
Something similar happens when you set the xaxis scale as logarithmic:
In this case, the first 3 point are ignored, since
log10([-Inf 0 0 0.0650 0.0650]) is [ Inf + 1.3644i -Inf -Inf -1.1871 -1.1871]
so, the first two point displayable on the graph are the fourth and the fifth which correspond to:
x=0.0650, y=0.4300
x=0.0650, y=0.4400
the first three point are then ignored.
As said at the beginning, this also happens for the setFive data set.
In this case you have:
x5= -Inf 0 0 0.0940 0.0940
y5= 0 0 0.1900 0.1900 0.2000
So in the first graph the first point is not diplayed and since
log10([ -Inf 0 0 0.0940 0.0940]) is Inf + 1.3644i -Inf -Inf -1.0269 -1.0269
the first three point will not be displayed in the second graph (log scale).
In conlcusion, you are right, some points are not diplayed in both the graphs but this is correct given the set of data to be displayed and the function you are using.
You can find below the two graphs zoomed to highlight the first point plotted (setFive in red, setSeven in black).
Zoom of the graph with xaxis linear scale
Zoom of the graph with xaxis logarithmic scale
Hope this helps.
Well it does exactly what it should do.
The cdf tries to generate a function that mimics the population distribution from the sample you gave it.
As a tule of thumb I prefer using the plot function, as it gives you more power and you are in complete control of the data.
So if you consider the below code and the figure it creates, it just means that in log space (where log(0) = -inf) you cannot plot any value of zero.
Therefore, only values that differ from zeros are viable, and the rest are omitted from the plot.
now if you find out these in the two data sets, using the following line
[min(cx5(cx5>0)),min(cx7(cx7>0))]
you will see that set five minimal value is much larger than set seven.
Now think on what is the log spacing when max is one, it emphasizes differences that are closer to zero on the expense of differences that are closer to one.
But as far as cdf's go these results are impressive.
Enjoy.
[cy5,cx5] = ecdf(setFive);
[cy7,cx7] = ecdf(setSeven);
subplot(221)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
axis([0 1 0 1])
subplot(222)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Yscale','log');
axis([0 1 0 1])
subplot(223)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Xscale','log');
axis([0 1 0 1])
subplot(224)
plot(cx5,cy5,'LineStyle','-','color','k');hold on
plot(cx7,cy7,'LineStyle','--','color','k');hold off
ylabel('F(x)'); xlabel('x');title('Empirical CDF');
set(gca,'Xscale','log','Yscale','log');
axis([0 1 0 1])

Subtracting two 3D patches/volumes from each other in Matlab

In my work, I have a nonuniform volume needs to be subtracted from my master volume/domain, and both volumes are discretized into particles, then a 3D visualization has to be constructed after the subtraction.
For a minimal example, if I have two cubes with vertices sets coordinates of
v1=[0 0 0;3 0 0;3 3 0;0 3 0;0 0 3;3 0 3;3 3 3;0 3 3]; % first cube
v2=[1 1 1;2 1 1;2 2 1;1 2 1;1 1 3;2 1 3;2 2 3;1 2 3]; % second cube
where v=[X,Y,Z] is the vertices 3D coordinates.
How can I subtract v2 from v1 and visualize the result?
P.S. I managed to create two patches as follows:
f1=convhulln(v1);
p1=patch('Vertices',v1,'Faces',f1);
f2=convhulln(v2);
p2=patch('Vertices',v2,'Faces',f2);
However, I couldn't figure out how to subtract them from each other.

Truncated gaussian kernel implementation Matlab,right?

I have the defination of Truncated gaussian kernel as:
So I confuse which is correct implementation of truncated gaussian kernel. Let see two case and let me know, thank you so much
Case 1:
G_truncated=fspecial('gaussian',round(2*sigma)*2 + 1,sigma); % kernel
Case 2:
G=fspecial('gaussian',round(2*sigma)*2 + 1,sigma); % normal distribution kernel
B = ones(round(2*sigma)*2 + 1,round(2*sigma)*2 + 1);
G_truncated=G.*B;
G_truncated = G_truncated/sum(G_truncated(:)); %normalized for sum=1
To add on to the previous post, there is a question of how to implement the kernel. You could use fspecial, truncate the kernel so that anything outside of the radius is zero, then renormalize it, but I'm assuming you'll want to do this from first principles.... so let's figure that out then. First, you need to generate a spatial map of distances from the centre of the mask. In conjunction, you use this to figure out what the Gaussian values (un-normalized) would be. You filter out those values in the un-normalized mask based on the spatial map of distances, then normalize that. As such, given your standard deviation tau, and your radius rho, you can do this:
%// Find grid of points
[X,Y] = meshgrid(-rho : rho, -rho : rho)
dists = (X.^2 + Y.^2); %// Find distances from the centre (Euclidean distance squared)
gaussVal = exp(-dists / (2*tau*tau)); %// Find unnormalized Gaussian values
%// Filter out those locations that are outside radius and set to 0
gaussVal(dists > rho^2) = 0;
%// Now normalize
gaussMask = gaussVal / (sum(gaussVal(:)));
Here is an example with using rho = 2 and tau = 2 with the outputs at each stage:
Stage #1 - Find grid co-ordinates
>> X
X =
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
>> Y
Y =
-2 -2 -2 -2 -2
-1 -1 -1 -1 -1
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
Step #2 - Find distances from centre and unnormalized Gaussian values
>> dists
dists =
8 5 4 5 8
5 2 1 2 5
4 1 0 1 4
5 2 1 2 5
8 5 4 5 8
>> gaussVal
gaussVal =
0.3679 0.5353 0.6065 0.5353 0.3679
0.5353 0.7788 0.8825 0.7788 0.5353
0.6065 0.8825 1.0000 0.8825 0.6065
0.5353 0.7788 0.8825 0.7788 0.5353
0.3679 0.5353 0.6065 0.5353 0.3679
Step #3 - Filter out locations that don't belong within the radius and set to 0
>> gaussVal =
0 0 0.6065 0 0
0 0.7788 0.8825 0.7788 0
0.6065 0.8825 1.0000 0.8825 0.6065
0 0.7788 0.8825 0.7788 0
0 0 0.6065 0 0
Step #4 - Normalize so sum is equal to 1
>> gaussMask =
0 0 0.0602 0 0
0 0.0773 0.0876 0.0773 0
0.0602 0.0876 0.0993 0.0876 0.0602
0 0.0773 0.0876 0.0773 0
0 0 0.0602 0 0
To verify that the mask sums to 1, just do sum(gaussMask(:)) and you'll see it's equal to 1... more or less :)
Your definition of truncated gaussian kernel is different than how MATLAB truncates filter kernels, though it generally won't matter in practice for sizable d.
fspecial already returns truncated AND normalized filter, so the second case is redundant, because it generates exactly the same result as case 1.
From MATLAB help:
H = fspecial('gaussian',HSIZE,SIGMA) returns a rotationally
symmetric Gaussian lowpass filter of size HSIZE with standard
deviation SIGMA (positive). HSIZE can be a vector specifying the
number of rows and columns in H or a scalar, in which case H is a
square matrix.
The default HSIZE is [3 3], the default SIGMA is 0.5.
You can use fspecial('gaussian',1,sigma) to generate a 1x1 filter and see that it is indeed normalized.
To generate a filter kernel that fits your definition, you need to make B in your second case a matrix that has ones in a circular area. A less strict (but nonetheless redundant in practice) solution is to use fspecial('disk',size) to truncate your gaussian kernel. Don't forget to normalize it in either case.
The answer of rayryeng is very useful for me. I only extend the gaussian kernel to ball kernel. The ball kernel is defined :
So based on answer of rayryeng. We can do it by
sigma=2;
rho=sigma;
tau=sigma;
%// Find grid of points
[X,Y] = meshgrid(-rho : rho, -rho : rho)
dists = (X.^2 + Y.^2); %// Find distances from the centre (Euclidean distance squared)
ballVal=dists;
ballVal(dists>sigma)=0;
ballVal(dists<=sigma)=1;
%// Now normalize
ballMask = ballVal / (sum(ballVal(:)));
Let me know, if it has any error or problem. Thank you

Avoiding sub2ind and ind2sub

I need to access several indices around a certain point in 3D.
For example, for point (x1,y1,z1) I need to get all the indices of its 3x3x3 neighborhood such that (x1,y1,z1) is centered. For neighborhood of size 3, I do it with
[x,y,z] = meshgrid(-1:1,-1:1,-1:1);
x_neighbors = bsxfun(#plus,x,x1);
y_neighbors = bsxfun(#plus,y,y1);
z_neighbors = bsxfun(#plus,z,z1);
Here, I center x1,y1,z1 to (0,0,0) by adding the distances from (x1,y1,z1) to any point in the 3x3x3 box.
that gives me the coordinates of (x1,y1,z1) 3x3x3 neighborhood. I then need to turn them into linear indices so I can access them:
lin_ind = sub2ind(size(volume),y_neighbors,x_neighbors,z_neighbors);
that is costly in what I do.
My question is, how to avoid sub2ind. If inx is the linear index of (x1,y1,z1),
inx = sub2ind(size(volume),y1,x1,z1);
how can I find the 3x3x3 neighborhood of the linear index by adding or subtracting or any other simple operation of inx?
As long as you know the dimensions of your 3D array, you can compute the linear offsets of all the elements of the 3x3x3 neighborhood. To illustrate this, consider a 2D example of a 4x5 matrix. The linear indices look like this:
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
The 3x3 neighborhood of 10 is [5 6 7 9 10 11 13 14 15]. The 3x3 neighborhood of 15 is [10 11 12 14 15 16 18 19 20]. If we subtract off the index of the central element, in both cases we get [-5 -4 -3 -1 0 1 3 4 5]. More generally, for MxN matrix we will have [-M-1 -M -M+1 -1 0 1 M-1 M M+1], or [(-M+[-1 0 1]) -1 0 1 (M+[-1 0 1])].
Generalizing to three dimensions, if the array is MxNxP, the linear index offsets from the central element will be [(-M*N+[-M-1 -M -M+1 -1 0 1 M-1 M M+1]) [-M-1 -M -M+1 -1 0 1 M-1 M M+1] (M*N+[-M-1 -M -M+1 -1 0 1 M-1 M M+1])]. You can reshape this to 3x3x3 if you wish.
Note that this sort of indexing doesn't deal well with edges; if you want to find the neighbors of an element on the edge of the array you should probably pad the array on all sides first (thereby changing M, N, and P).
Just adding the (generalized) code to #nhowe answer:
This is an example for neighborhood of size 5X5X5, therefore r (the radius) is 2:
ns = 5;
r = 2;
[M,N,D] = size(vol);
rs = (1:ns)-(r+1);
% 2d generic coordinates:
neigh2d = bsxfun(#plus, M*rs,rs');
% 3d generic coordinates:
pages = (M*N)*rs;
pages = reshape(pages,1,1,length(pages));
neigh3d = bsxfun(#plus,neigh2d,pages);
to get any neighborhood of any linear index of vol, just add the linear index to neigh3d:
new_neigh = bxsfun(#plus,neigh3d, lin_index);