How to precisely orient a Camera in Graphics3D? - wolfram-mathematica

For a simulation of a laser-based sensor I am designing, I want to verify how four points projected on a surface would appear from a camera. And so I have undertaken to implement a Graphics3D visualization.
The visualization places 4 lasers in a pyramid-like arrangement with a camera 20 centimeters two one side viewing the laser's projections. My notebook code produces two views: one outside a room the sensor would operate within and a second view point which represents the camera which is rotated with the lasers. The Euler angles and x,y,z coordinates of the camera-laser ensemble can be controlled using sliders.
My problem is that in the simulation the camera is be being automatically oriented. And so the view from a real physical camera is not reproduced because Mathematica is adjusting the viewpoint. If the camera and laser rotated together than rotations in Psi would cause the camera to rotate in lockstep with the laser and the view should be unchanged. Likewise shifts in x and y shouldn't make the camera jiggle so.
How can I control the camera orientation to produce a more coherent simulation?
The notebook code is:
\[Delta] = N[(38*Degree)/2];
PointPlaneIntersection[{{x1_, y1_, z1_},
{x2_, y2_, z2_}, {x3_, y3_, z3_}},
{{x4_, y4_, z4_}, {x5_, y5_, z5_}}] :=
Module[{t = -Det[{{1, 1, 1, 1}, {x1, x2, x3, x4},
{y1, y2, y3, y4}, {z1, z2, z3, z4}}]/
Det[{{1, 1, 1, 0}, {x1, x2, x3, x5 - x4},
{y1, y2, y3, y5 - y4}, {z1, z2, z3,
z5 - z4}}]}, Point[{x4 + t*(x5 - x4),
y4 + t*(y5 - y4), z4 + t*(z5 - z4)}]];
UnitSpherePoint[azimuth_, polar_] :=
{Cos[azimuth]*Sin[polar], Sin[azimuth]*Sin[polar],
Cos[polar]};
Manipulate[rx := RotationMatrix[\[Theta], {1, 0, 0}];
ry := RotationMatrix[\[Phi], {0, 1, 0}];
rz := RotationMatrix[\[Psi], {0, 0, 1}];
line1 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[0,
Pi + \[Delta]] + {x, y, z}};
line2 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
Pi/2, Pi + \[Delta]] + {x, y, z}};
line3 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
Pi, Pi + \[Delta]] + {x, y, z}};
line4 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
3*(Pi/2), Pi + \[Delta]] + {x, y, z}};
cline = {{x + 0.2, y, z},
rx . ry . rz . UnitSpherePoint[0, Pi] +
{x + 0.2, y, z}}; roomplane :=
{{0, 0, 0}, {30, 0, 0}, {0, 15, 0}};
Scene := Graphics3D[{Red, Opacity[1],
PointPlaneIntersection[roomplane, line1],
PointPlaneIntersection[roomplane, line2],
PointPlaneIntersection[roomplane, line3],
PointPlaneIntersection[roomplane, line4], White,
Opacity[0.1], Cuboid[{0, 0, 0}, {30, 15, 6}]},
Boxed -> False, Lighting -> "Neutral"];
Grid[{{Show[Scene], Show[Scene, ViewVector -> cline,
ViewAngle -> 64*Degree, RotationAction ->
"Clip"]}}], {{x, 15}, 0, 30}, {{y, 7.5}, 0, 15},
{{z, 3}, 0, 6}, {{\[Theta], Pi}, 0, 2*Pi},
{{\[Phi], Pi}, 0, 2*Pi}, {{\[Psi], Pi}, 0, 2*Pi}]

As I guess you are fully aware, you need to somehow specify the camera position, orientation and angle of view. In typical Mathematica fashion, you can do this by specifying a million different subsets of interrelated options. The following is how I would do it:
Firstly, the camera position. This can be specified in graphics coordinates (ViewVector) or relative to the bounding box (ViewPoint). Either of these should work. While specifying the camera position, remember that the perspective effects diminish when you move further away from ViewCenter.
The camera orientation is defined by the ViewCenter (specifying 2 degrees of the camera orientation) and ViewVertical (the direction that will end up being vertical in the 2D projection). ViewCenter is usually fine by default if you have specified a PlotRange.
Finally, Automatic is most often fine for ViewAngle if you have a well defined PlotRange, but you might need to set SphericalRegion to true if you are moving around your subject.
All the view geometry options are listed here, but I guess ViewRange is about the only one I haven't mentioned above :). As far as I can tell, you just need to specify ViewVertical?

I think that all you need to do is instead of using the ViewVector option, set
ViewPoint -> {x, y, z}
Some of the jiggling is due to the laser/plane intersection points moving too far out of the room. It might be best to truncate these somehow.
Aside: your code calculates rx . ry . rz five times, it's probably best to calculate it once and store it.

Related

How to make a program in mathematica that gives us the radius of a drop from the theoretical profile of that drop?

How to make a program in Mathematica that is able to recognize this image and return the radius of the circular part of it?
While curve extraction is possible the radius can be obtained quite simply, i.e.
img = Import["https://i.stack.imgur.com/LENuK.jpg"];
{wd, ht} = ImageDimensions[img];
data = ImageData[img];
p1 = LengthWhile[data[[-33]], # == {1., 1., 1.} &];
p2 = LengthWhile[Reverse[data[[-33]]], # == {1., 1., 1.} &];
p120 = wd - p1 - p2 - 1;
p3 = LengthWhile[data[[-245]], # == {1., 1., 1.} &];
p4 = LengthWhile[Reverse[data[[-245]]], # == {1., 1., 1.} &];
pdrop = wd - p3 - p4 - 1;
radius = 120/p120*pdrop/2.
55.814
Further automation could automatically detect the widest point of the drop, which is here found by testing: line 245 (see sample lines in bottom image).
Making sense of the scale could be difficult to automate. We can see the outermost ticks are at -60 & 60, a length of 120 which turns out to be 400 pixels, pdrop.
As the sketch below shows, the circular part of the drop is limited by the widest points, so that length and the scale are all that is needed to find the radius.
Two lines are used to find the image scale and outer bounds of the drop: line 33 and 245, shown below coloured red.
Additional code
In the code below r is calibrated against the scale so that it equals 60.
img = Import["https://i.stack.imgur.com/LENuK.jpg"];
{wd, ht} = ImageDimensions[img];
Manipulate[
Graphics[{Rectangle[{0, 0}, {wd, ht}],
Inset[img, {0, 0}, {0, 0}, {wd, ht}],
Inset[Graphics[{Circle[{x, y}, r]},
ImageSize -> {wd, ht}, PlotRange -> {{0, wd}, {0, ht}}],
{0, 0}, {0, 0}, {wd, ht}],
Inset[
Style["r = " <> ToString[Round[60 r/212.8, 0.1]], 16],
{50, 510}]},
ImageSize -> {wd, ht}, PlotRange -> {{0, wd}, {0, ht}}],
{{x, 228}, 0, 300}, {{y, 247}, 0, 300}, {{r, 196}, 0, 300}]

Can we generate "foveated Image" in Mathematica

"Foveated imaging is a digital image processing technique in which the image resolution, or amount of detail, varies across the image according to one or more "fixation points." A fixation point indicates the highest resolution region of the image and corresponds to the center of the eye's retina, the fovea."
I want to use such image to illustrate humans visual acuity, The bellow diagram shows the relative acuity of the left human eye (horizontal section) in degrees from the fovea (Wikipedia) :
Is there a way to create a foveated image in Mathematica using its image processing capabilities ?
Something along the following lines may work for you. The filtering details should be adjusted to your tastes.
lena = ExampleData[{"TestImage", "Lena"}]
ImageDimensions[lena]
==> {512, 512}
mask = DensityPlot[-Exp[-(x^2 + y^2)/5], {x, -4, 4}, {y, -4, 4},
Axes -> None, Frame -> None, Method -> {"ShrinkWrap" -> True},
ColorFunction -> GrayLevel, ImageSize -> 512]
Show[ImageFilter[Mean[Flatten[#]] &, lena, 20, Masking -> mask], ImageSize -> 512]
Following on Sjoerd's answer, you can Fold[] a radius-dependent blur as follows.
A model for the acuity (very rough model):
Clear[acuity];
acuity[distance_, x_, y_, blindspotradius_] :=
With[{\[Theta] = ArcTan[distance, Sqrt[x^2 + y^2]]},
Clip[(Chop#Exp[-Abs[\[Theta]]/(15. Degree)] - .05)/.95,
{0,1}] (1. - Boole[(x + 100.)^2 + y^2 <= blindspotradius^2])]
Plot3D[acuity[250., x, y, 25], {x, -256, 256}, {y, -256, 256},
PlotRange -> All, PlotPoints -> 40, ExclusionsStyle -> Automatic]
The example image:
size = 100;
lena = ImageResize[ExampleData[{"TestImage", "Lena"}], size];
Manipulate[
ImageResize[
Fold[Function[{ima, r},
ImageFilter[(Mean[Flatten[#]] &), ima,
7*(1 - acuity[size*5, r, 0, 0]),
Masking -> Graphics[Disk[p/2, r],
PlotRange -> {{0, size}, {0, size}}]
]],
lena, Range[10, size, 5]],
200],
{{p, {size, size}}, Locator}]
Some examples:
WaveletMapIndexed can give a spatially-varying blur, as shown in the Mathematica documentation (WaveletMapIndexed->Examples->Applications->Image Processing). Here is an implementation of a foveatedBlur, using a compiled version of the acuity function from the other answer:
Clear[foveatedBlur];
foveatedBlur[image_, d_, cx_, cy_, blindspotradius_] :=
Module[{sx, sy},
{sy, sx} = ImageDimensions#image;
InverseWaveletTransform#WaveletMapIndexed[ImageMultiply[#,
Image[acuityC[d, sx, sy, -cy + sy/2, cx - sx/2, blindspotradius]]] &,
StationaryWaveletTransform[image, Automatic, 6], {___, 1 | 2 | 3 | 4 | 5 | 6}]]
where the compiled acuity is
Clear[acuityC];
acuityC = Compile[{{distance, _Real}, {sx, _Integer}, {sy, _Integer}, {x0, _Real},
{y0, _Real}, {blindspotradius, _Real}},
Table[With[{\[Theta] = ArcTan[distance, Sqrt[(x - x0)^2 + (y - y0)^2]]},
(Exp[-Abs[\[Theta]]/(15 Degree)] - .05)/.95
*(1. - Boole[(x - x0)^2 + (y - y0 + 0.25 sy)^2 <= blindspotradius^2])],
{x, Floor[-sx/2], Floor[sx/2 - 1]}, {y, Floor[-sy/2], Floor[sy/2 - 1]}]];
The distance parameter sets the rate of falloff of the acuity. Focusing point {cx,cy}, and blind-spot radius are self-explanatory. Here is an example using Manipulate, looking right at Lena's right eye:
size = 256;
lena = ImageResize[ExampleData[{"TestImage", "Lena"}], size];
Manipulate[foveatedBlur[lena, d, p[[1]], p[[2]], 20], {{d, 250}, 50,
500}, {{p, ImageDimensions#lena/2}, Locator, Appearance -> None}]
See the blind spot?

Extract contours from ContourPlot in Mathematica

I have a function f(x,y) of two variables, of which I need to know the location of the curves at which it crosses zero. ContourPlot does that very efficiently (that is: it uses clever multi-grid methods, not just a brute force fine-grained scan) but just gives me a plot. I would like to have a set of values {x,y} (with some specified resolution) or perhaps some interpolating function which allows me to get access to the location of these contours.
Have thought of extracting this from the FullForm of ContourPlot but this seems to be a bit of a hack. Any better way to do this?
If you end up extracting points from ContourPlot, this is one easy way to do it:
points = Cases[
Normal#ContourPlot[Sin[x] Sin[y] == 1/2, {x, -3, 3}, {y, -3, 3}],
Line[pts_] -> pts,
Infinity
]
Join ## points (* if you don't want disjoint components to be separate *)
EDIT
It appears that ContourPlot does not produce very precise contours. They're of course meant for plotting and are good enough for that, but the points don't lie precisely on the contours:
In[78]:= Take[Join ## points /. {x_, y_} -> Sin[x] Sin[y] - 1/2, 10]
Out[78]= {0.000163608, 0.0000781187, 0.000522698, 0.000516078,
0.000282781, 0.000659909, 0.000626086, 0.0000917416, 0.000470424,
0.0000545409}
We can try to come up with our own method to trace the contour, but it's a lot of trouble to do it in a general way. Here's a concept that works for smoothly varying functions that have smooth contours:
Start from some point (pt0), and find the intersection with the contour along the gradient of f.
Now we have a point on the contour. Move along the tangent of the contour by a fixed step (resolution), then repeat from step 1.
Here's a basic implementation that only works with functions that can be differentiated symbolically:
rot90[{x_, y_}] := {y, -x}
step[f_, pt : {x_, y_}, pt0 : {x0_, y0_}, resolution_] :=
Module[
{grad, grad0, t, contourPoint},
grad = D[f, {pt}];
grad0 = grad /. Thread[pt -> pt0];
contourPoint =
grad0 t + pt0 /. First#FindRoot[f /. Thread[pt -> grad0 t + pt0], {t, 0}];
Sow[contourPoint];
grad = grad /. Thread[pt -> contourPoint];
contourPoint + rot90[grad] resolution
]
result = Reap[
NestList[step[Sin[x] Sin[y] - 1/2, {x, y}, #, .5] &, {1, 1}, 20]
];
ListPlot[{result[[1]], result[[-1, 1]]}, PlotStyle -> {Red, Black},
Joined -> True, AspectRatio -> Automatic, PlotMarkers -> Automatic]
The red points are the "starting points", while the black points are the trace of the contour.
EDIT 2
Perhaps it's an easier and better solution to use a similar technique to make the points that we get from ContourPlot more precise. Start from the initial point, then move along the gradient until we intersect the contour.
Note that this implementation will also work with functions that can't be differentiated symbolically. Just define the function as f[x_?NumericQ, y_?NumericQ] := ... if this is the case.
f[x_, y_] := Sin[x] Sin[y] - 1/2
refine[f_, pt0 : {x_, y_}] :=
Module[{grad, t},
grad = N[{Derivative[1, 0][f][x, y], Derivative[0, 1][f][x, y]}];
pt0 + grad*t /. FindRoot[f ## (pt0 + grad*t), {t, 0}]
]
points = Join ## Cases[
Normal#ContourPlot[f[x, y] == 0, {x, -3, 3}, {y, -3, 3}],
Line[pts_] -> pts,
Infinity
]
refine[f, #] & /# points
A slight variation for extracting points from ContourPlot (possibly due to David Park):
pts = Cases[
ContourPlot[Cos[x] + Cos[y] == 1/2, {x, 0, 4 Pi}, {y, 0, 4 Pi}],
x_GraphicsComplex :> First#x, Infinity];
or (as a list of {x,y} points)
ptsXY = Cases[
Cases[ContourPlot[
Cos[x] + Cos[y] == 1/2, {x, 0, 4 Pi}, {y, 0, 4 Pi}],
x_GraphicsComplex :> First#x, Infinity], {x_, y_}, Infinity];
Edit
As discussed here, an article by Paul Abbott in the Mathematica Journal (Finding Roots in an Interval) gives the following two alternative methods for obtaining a list of {x,y} values from ContourPlot, including (!)
ContourPlot[...][[1, 1]]
For the above example
ptsXY2 = ContourPlot[
Cos[x] + Cos[y] == 1/2, {x, 0, 4 Pi}, {y, 0, 4 Pi}][[1, 1]];
and
ptsXY3 = Cases[
Normal#ContourPlot[
Cos[x] + Cos[y] == 1/2, {x, 0, 4 Pi}, {y, 0, 4 Pi}],
Line[{x__}] :> x, Infinity];
where
ptsXY2 == ptsXY == ptsXY3

Is it possible to create polar CountourPlot/ListCountourPlot/DensityPlot in Mathematica?

I am looking to plot something like the whispering gallery modes -- a 2D cylindrically symmetric plot in polar coordinates. Something like this:
I found the following code snippet in Trott's symbolics guidebook. Tried running it on a very small data set; it ate 4 GB of memory and hosed my kernel:
(* add points to get smooth curves *)
addPoints[lp_][points_, \[Delta]\[CurlyEpsilon]_] :=
Module[{n, l}, Join ## (Function[pair,
If[(* additional points needed? *)
(l = Sqrt[#. #]&[Subtract ## pair]) < \[Delta]\[CurlyEpsilon], pair,
n = Floor[l/\[Delta]\[CurlyEpsilon]] + 1;
Table[# + i/n (#2 - #1), {i, 0, n - 1}]& ## pair]] /#
Partition[If[lp === Polygon,
Append[#, First[#]], #]&[points], 2, 1])]
(* Make the plot circular *)
With[{\[Delta]\[CurlyEpsilon] = 0.1, R = 10},
Show[{gr /. (lp : (Polygon | Line))[l_] :>
lp[{#2 Cos[#1], #2 Sin[#1]} & ###(* add points *)
addPoints[lp][l, \[Delta]\[CurlyEpsilon]]],
Graphics[{Thickness[0.01], GrayLevel[0], Circle[{0, 0}, R]}]},
DisplayFunction -> $DisplayFunction, Frame -> False]]
Here, gr is a rectangular 2D ListContourPlot, generated using something like this (for example):
data = With[{eth = 2, er = 2, wc = 1, m = 4},
Table[Re[
BesselJ[(Sqrt[eth] m)/Sqrt[er], Sqrt[eth] r wc] Exp[
I m phi]], {r, 0, 10, .2}, {phi, 0, 2 Pi, 0.1}]];
gr = ListContourPlot[data, Contours -> 50, ContourLines -> False,
DataRange -> {{0, 2 Pi}, {0, 10}}, DisplayFunction -> Identity,
ContourStyle -> {Thickness[0.002]}, PlotRange -> All,
ColorFunctionScaling -> False]
Is there a straightforward way to do cylindrical plots like this?.. I find it hard to believe that I would have to turn to Matlab for my curvilinear coordinate needs :)
Previous snippets deleted, since this is clearly the best answer I came up with:
With[{eth = 2, er = 2, wc = 1, m = 4},
ContourPlot[
Re[BesselJ[(Sqrt[eth] m)/Sqrt[er], Sqrt[eth] r wc] Exp[I phi m]]/.
{r ->Norm[{x, y}], phi ->ArcTan[x, y]},
{x, -10, 10}, {y, -10, 10},
Contours -> 50, ContourLines -> False,
RegionFunction -> (#1^2 + #2^2 < 100 &),
ColorFunction -> "SunsetColors"
]
]
Edit
Replacing ContourPlot by Plot3D and removing the unsupported options you get:
This is a relatively straightforward problem. The key is that if you can parametrize it, you can plot it. According to the documentation both ListContourPlot and ListDensityPlot accept data in two forms: an array of height values or a list of coordinates plus function value ({{x, y, f} ..}). The second form is easier to deal with, such that even if your data is in the first form, we'll transform it into the second form.
Simply, to transform data of the form {{r, t, f} ..} into data of the form {{x, y, f} ..} you doN[{#[[1]] Cos[ #[[2]] ], #[[1]] Sin[ #[[2]] ], #[[3]]}]& /# data, when applied to data taken from BesselJ[1, r/2] Cos[3 t] you get
What about when you just have an array of data, like this guy? In that case, you have a 2D array where each point in the array has known location, and in order to plot it, you have to turn it into the second form. I'm partial to MapIndexed, but there are other ways of doing it. Let's say your data is stored in an array where the rows correspond to the radial coordinate and the columns are the angular coordinate. Then to transform it, I'd use
R = 0.01; (*radial increment*)
T = 0.05 Pi; (*angular increment*)
xformed = MapIndexed[
With[{r = #2[[1]]*R, t = #2[[1]]*t, f = #1},
{r Cos[t], r Sin[t], f}]&, data, {2}]//Flatten[#,1]&
which gives the same result.
If you have an analytic solution, then you need to transform it to Cartesian coordinates, like above, but you use replacement rules, instead. For instance,
ContourPlot[ Evaluate[
BesselJ[1, r/2]*Cos[3 t ] /. {r -> Sqrt[x^2 + y^2], t -> ArcTan[x, y]}],
{x, -5, 5}, {y, -5, 5}, PlotPoints -> 50,
ColorFunction -> ColorData["DarkRainbow"], Contours -> 25]
gives
Two things to note: 1) Evaluate is needed to ensure that the replacement is performed correctly, and 2) ArcTan[x, y] takes into account the quadrant that the point {x,y} is found in.

how to animate 3d plot given a rotation axis in mathematics

If given a rotation axis normalized, such as {1/Sqrt[3],1/Sqrt[3],1/Sqrt[3]}, and a 3d plot, for example,
z[x_, y_] := Exp[-(Sqrt[x^2 + y^2]/Power[4, (3)^-1]) +
Power[4, (3)^-1]*Sqrt[1/2*(Sqrt[x^2 + y^2] + x)]];
Plot3D[2*z[x, y], {x, -5, 5}, {y, -5, 5}]
I want to create an animation for this plot about the axis {1/Sqrt[3],1/Sqrt[3],1/Sqrt[3]} (could be any other arbitary one), and then export it as an animated gif. Would anyone please help? Many thanks.
Edit
I also left out one degree of freedom in specifying the rotation. Could any one please help, if also given the coordinate of a point which the rotational axis must pass, how to do the visualization/animation?
Thanks again.
Copying what Daniel did, just prepared for exporting.
axis = {1, 1, 1};
l = {-7, 7};
s = Table[
Plot3D[2*z[x, y], {x, -5, 5}, {y, -5, 5}, PlotRange -> {l, l, l}] /.
gg : GraphicsComplex[___] :> Rotate[gg, theta, axis], {theta, 0., 2. Pi}];
Export["c:\\test.gif", s]
The following parameters are available for the gif export (as per the docs):
"AnimationRepetitions" how many times the animation is played before stopping
"Background" background color shown in transparent image regions
"BitDepth" bits used to represent each color channel in the file
"ColorMap" color reduction palette, given as a list of color values
"GlobalColorMap" default color palette for individual animation frames
"DisplayDurations" display durations of animation frames, given in seconds
"ImageCount" number of frames in an animated GIF
"ImageSize" overall image size
"RawData" array of color map indices
"Comments" user comments stored in the file
I used "DisplayDurations" in the past, and it worked.
Could do as below.
axis = {1, 1, 1};
Animate[
Plot3D[2*z[x, y], {x, -5, 5}, {y, -5, 5}] /.
gg : GraphicsComplex[___] :> Rotate[gg, theta, axis],
{theta, 0., 2.*Pi}]
Daniel Lichtblau
Wolfram Research

Resources