ILNumerics ILSurface Adjust Z values - ilnumerics

Is there a way to manipulate the range of Z values for a Surface plot in a way that can preserve the original values so I can create a range slider with a min and max values from the GetLimits() method and then update the data array Z values so I can set new limits but move the slides back and forth to adjust the min/max Z value and see the plot adjust as I do it?
Given this code
ILArray<float> tempArray = ILMath.tosingle(myDoubleArray);
dataArray.a = tempArray;
var plotCube = ilPanel1.Scene.First<ILPlotCube>();
var surface = plotCube.First<ILFastSurface>();
surface.Update(Z: dataArray, colormap: new ILColormap(ILColormaps.ILNumerics));
ilPanel1.Refresh();
The MinValue and MaxValue controls are initialized like this.
float maxZ, minZ;
dataArray.GetLimits(out minZ, out maxZ);
var zRange = maxZ - minZ;
MinValue.Maximum = (decimal)maxZ;
MinValue.Minimum = (decimal)minZ;
MinValue.Value = (decimal)minZ;
MaxValue.Maximum = (decimal)maxZ;
MaxValue.Minimum = (decimal)minZ;
MaxValue.Value = (decimal)maxZ;
I want to be able to manipulate the Z values in the array like this
dataArray[dataArray < (float)MinValue.Value] = (float)MinValue.Value;
dataArray[dataArray > (float)MaxValue.Value] = (float)MaxValue.Value;
var plotCube = ilPanel1.Scene.First<ILPlotCube>();
var surface = plotCube.First<ILFastSurface>();
surface.Update(Z: dataArray, colormap: new ILColormap(ILColormaps.ILNumerics));
ilPanel1.Refresh();
The issue is that dataArray is being changed with new min/max values. How can I restore dataArray if you want to change back to a larger min/max? Do I just clone dataArray and use that to change the plot? Or is there a feature of ILArray that tracks changes and can restore the array?

The solution to this problem is to use a temporary array and clone the original array and then normalize the temporary array and update the surface with it.
float min = surface.GetRangeMinValue(AxisNames.CAxis) + minOffs;
float max = surface.GetRangeMaxValue(AxisNames.CAxis) + maxOffs;
ILArray<float> tempArray = _dataArray.C;
tempArray[tempArray < min] = min;
tempArray[tempArray > max] = max;
surface.Update(Z: tempArray);
_dataArray is a static property loaded once with the original data. Any updates are done with the code above

Related

Resize Frame for Optical Flow

I have problem with optical flow if the frame size have been manipulated in any way this gives me error. There are two options either change the resolution of the video at the beginning or somehow how change the frame size in a way that optical flow will work. I will want to add a cascade object to detect nose, mouth and eyes in further development therefore I need solution that will work for individual regions without necessary setting optical flow individually for those regions especially that a bounding box does not have a fixed size and it will displace itself slightly from frame to frame. Here is my code so far, the error is that it is exceeding matrix dimensions.
faceDetector = vision.CascadeObjectDetector();
vidObj = vision.VideoFileReader('MEXTest.mp4','ImageColorSpace','Intensity','VideoOutputDataType','uint8');
converter = vision.ImageDataTypeConverter;
opticalFlow = vision.OpticalFlow('ReferenceFrameDelay', 1);
opticalFlow.OutputValue = 'Horizontal and vertical components in complex form';
shapeInserter = vision.ShapeInserter('Shape','Lines','BorderColor','Custom','CustomBorderColor', 255);
vidPlayer = vision.VideoPlayer('Name','Motion Vector');
while ~isDone(vidObj);
frame = step(vidObj);
fraRes = imresize(frame,0.5);
fbbox = step(faceDetector,fraRes);
I = imcrop(fraRes,fbbox);
im = step(converter,I);
of = step(opticalFlow,im);
lines = videooptflowlines(of, 20);
if ~isempty(lines)
out = step(shapeInserter,im,lines);
step(vidPlayer,out);
end
end
release(vidPlayer);
release(VidObj);
UPDATE: I went and edited the function for optical flow which creates lines and this sorts out the some size issues however it is necessary to to input this manually for each object (so if there is any other way let me know). I think the best solution would be set a fixed size to cascadeObjectDetector, does anyone know how to do this? Or have any other idea?
faceDetector = vision.CascadeObjectDetector(); %I need fixed size for this
faceDetector.MinSize = [150 150];
vidRead = vision.VideoFileReader('MEXTest.mp4','ImageColorSpace','Intensity','VideoOutputDataType','uint8');
convert = vision.ImageDataTypeConverter;
optFlo = vision.OpticalFlow('ReferenceFrameDelay', 1);
optFlo.OutputValue = 'Horizontal and vertical components in complex form';
shapeInserter = vision.ShapeInserter('Shape','Lines','BorderColor','Custom', 'CustomBorderColor', 255);
while ~isDone(vidRead)
frame = step(vidRead);
fraRes = imresize(frame,0.3);
fraSin = im2single(fraRes);
bbox = step(faceDetector,fraSin);
I = imcrop(fraSin, bbox);
im = step(convert, I);
release(optFlo);
of = step(optFlo, im);
lines = optfloo(of, 50); %use videooptflowlines instead of (optfloo)
out = step(shapeInserter, im, lines);
imshow(out);
end

Bad Orientation of Principal Axis of a Point Cloud

I'm trying to calculate the principal axis via principal component analysis. I have a pointcloud and use for this the Point Cloud Library (pcl). Furthermore, I try to visualize the principal axis I calculated in rviz with markers. Here is the code snipped I use:
void computePrincipalAxis(const PointCloud& cloud, Eigen::Vector4f& centroid, Eigen::Matrix3f& evecs, Eigen::Vector3f& evals) {
Eigen::Matrix3f covariance_matrix;
pcl::computeCovarianceMatrix(cloud, centroid, covariance_matrix);
pcl::eigen33(covariance_matrix, evecs, evals);
}
void createArrowMarker(Eigen::Vector3f& vec, int id, double length) {
visualization_msgs::Marker marker;
marker.header.frame_id = frameId;
marker.header.stamp = ros::Time();
marker.id = id;
marker.type = visualization_msgs::Marker::ARROW;
marker.action = visualization_msgs::Marker::ADD;
marker.pose.position.x = centroid[0];
marker.pose.position.y = centroid[1];
marker.pose.position.z = centroid[2];
marker.pose.orientation.x = vec[0];
marker.pose.orientation.y = vec[1];
marker.pose.orientation.z = vec[2];
marker.pose.orientation.w = 1.0;
marker.scale.x = length;
marker.scale.y = 0.02;
marker.scale.z = 0.02;
marker.color.a = 1.0;
marker.color.r = 1.0;
marker.color.g = 1.0;
marker.color.b = 0.0;
featureVis.markers.push_back(marker);
}
Eigen::Vector4f centroid;
Eigen::Matrix3f evecs;
Eigen::Vector3f evals;
// Table is the pointcloud of the table only.
pcl::compute3DCentroid(*table, centroid);
computePrincipalAxis(*table, centroid, evecs, evals);
Eigen::Vector3f vec;
vec << evecs.col(0);
createArrowMarker(vec, 1, evals[0]);
vec << evecs.col(1);
createArrowMarker(vec, 2, evals[1]);
vec << evecs.col(2);
createArrowMarker(vec, 3, evals[2]);
publish();
This results in the following visualization:
I'm aware that the scale is not very perfect. The two longer arrows are much too long. But I'm confused about a few things:
I think the small arrow should go either up, or downwards.
What does the value orientation.w of the arrow's orientation mean?
Do you have some hints what I did wrong?
Orientations are represented by Quaternions in ROS, not by directional vectors. Quaternions can be a bit unintuitive, but fortunately there are some helper functions in the tf package, to generate quaternions, for example, from roll/pitch/yaw-angles.
One way to fix the marker would therefore be, to convert the direction vector into a quaternion.
In your special case, there is a much simpler solution, though: Instead of setting origin and orientation of the arrow, it is also possible to define start and end point (see ROS wiki about marker types). So instead of setting the pose attribute, just add start and end point to the points attribute:
float k = 1.0; // optional to scale the length of the arrows
geometry_msgs::Point p;
p.x = centroid[0];
p.y = centroid[1];
p.z = centroid[2];
marker.points.push_back(p);
p.x += k * vec[0];
p.y += k * vec[1];
p.z += k * vec[2];
marker.points.push_back(p);
You can set k to some value < 1 to reduce the length of the arrows.

Error in loop in Matlab, calculate position

GOAL:
In this project, we calculate the gravitational forces exerted by each body in a solar system on the other bodies in the system. Based upon those forces and initial position/velocities of the bodies, one can predict their motion using Newton’s second law. We assume that the following information is given:
The masses of all bodies involved in a solar system.
The positions and velocities of all planets at a given time.
Then we can calculate the gravitational forces using Newton’s law of universal gravitation. Each body is acted upon by gravitational forces from all the other bodies, and therefore the total force on the body is the sum of the forces induced by all the other bodies. Once the force on a body is known, the acceleration of each body can be determined using Newton’s second law of motion. Based upon this acceleration at any time t, we can calculate the new velocity and position of the bodies at time t + ∆t. We start with known positions and velocities at time t = 0, then calculate those at ∆t, then at 2∆t and so on.
ASSIGNMENT:
Write a MATLAB function that takes as input a struct array (where each element represents one body in your solar system), a time step ∆t and a final time T. Each struct in the struct array should have the following fields:
name: A string that holds the name of the planet.
x: The x-coordinate of the initial position of the planet.
y: The y-coordinate of the initial position of the planet.
z: The z-coordinate of the initial position of the planet.
vx: The x-component of the initial velocity of the planet.
vy: The y-component of the initial velocity of the planet.
vz: The z-component of the initial velocity of the planet.
Then your function should use the model of a gravitational system described above to compute the positions and velocities of all planets at all times. Your function should return these values in an appropriate way and also produce a plot of the positions of all planets in a 3D plot. The plot should at least contain a title and a legend. The legend should use the field name in order to name each planet. Further, each planet should be shown in a different color where the color is determined randomly. A sample plot is given in Figure 1.
MY ERROR
There is an error in my last loop with time in it, has n=1:T/t; regarding matrix dimensions. I'm trying to calculate new forces using the updated positions from each iteration, however I am getting and error, and my plot shows a bunch of straight lines, and not a solar system orbit.**
function [x, y, z, vx, vy, vz] = solarsystemsim(F,t,T)
m = size(F,2);
G = 6.67384e-11;
j=1;
x = 1:10;
% r = zeros(m-1,1);
% gF = zeros(m-1,1);
for(i=1:m)
for(j=1:m)
r(i,j) = distform2(F(i).x,F(j).x,F(i).y,F(j).y,F(i).z,F(j).z);
gF(i,j) = (G*(F(i).mass)*(F(j).mass))/((r(i,j))^2);
gFx(i,j) = -((gF(i,j))*(F(i).x-F(j).x))/(r(i,j));
gFy(i,j) = -((gF(i,j))*(F(i).y-F(j).y))/(r(i,j));
gFz(i,j) = -((gF(i,j))*(F(i).z-F(j).z))/(r(i,j));
if(i==j)
gF(i,j) = 0;
gFx(i,j) = 0;
gFy(i,j) = 0;
gFz(i,j) = 0;
end
end
end
for(i=1:m)
gFxT(i) = sum(gFx(i,:));
gFyT(i) = sum(gFy(i,:));
gFzT(i) = sum(gFz(i,:));
end
tn = 0;
n = 1;
x = zeros(T/t,m);
y = zeros(T/t,m);
z = zeros(T/t,m);
vx = zeros(T/t,m);
vy = zeros(T/t,m);
vz = zeros(T/t,m);
for(i=1:m)
vx(1,i) = F(i).vx;
vy(1,i) = F(i).vy;
vz(1,i) = F(i).vz;
x(1,i) = F(i).x;
y(1,i) = F(i).y;
z(1,i) = F(i).z;
end
for(n=1:T/t)
for(i=1:m)
for(j=1:m)
r(i+1,j+1) = distform2(x(i,j),x(i,j),y(i,j),y(i,j),z(i,j),z(i,j));
gF(i+1,j+1) = (G*(F(i).mass)*(F(j).mass))/((r(i,j))^2);
gFx(i+1,j+1) = -((gF(i,j))*(x(i,j)-x(i,j+1)))/(r(i,j));
gFy(i+1,j+1) = -((gF(i,j))*(y(i,j)-y(i,j+1)))/(r(i,j));
gFz(i+1,j+1) = -((gF(i,j))*(z(i,j)-z(i,j+1)))/(r(i,j));
if(i==j)
gF(i,j) = 0;
gFx(i,j) = 0;
gFy(i,j) = 0;
gFz(i,j) = 0;
end
end
end
gFxT(i) = sum(gFx(i,:));
gFyT(i) = sum(gFy(i,:));
gFzT(i) = sum(gFz(i,:));
for(i=1:T/t)
for(j=1:m)
vx(i,j) = vx(i,j) + t*(gFxT(j))/(F(j).mass);
vy(i,j) = vy(i,j) + t*(gFyT(j))/(F(j).mass);
vz(i,j) = vz(i,j) + t*(gFzT(j))/(F(j).mass);
x(i,j) = x(i,j) + t*(vx(j));
y(i,j) = y(i,j) + t*(vy(j));
z(i,j) = z(i,j) + t*(vz(j));
end
end
plot3(x,y,z);
end
F is not a matrix and so you can't index it using parentheses. It's a cell array and must be indexed using braces {}
EDITED to correct struct to cell as per lmillefiori's comment

Changing the axis range dynamically doesnt refresh the lineplot but only the axis labels

I am trying to change the axes Min and Max properties to show only the plot points that lie in a particular range.
say If I have lineplot whose X values are ranging from 0 to 100, I want to display only the values that are greater than 50.However I noticed that the lineplot is drawn using all the position points.Only the x axis ticks got renamed such that they start from 50 and end at 100.
The following is the code I am using
var axes = m_plotCube.First<ILAxisCollection>();
if (axes != null)
{
ILAxis xAxis = axes.Where<ILAxis>(item => item.Label.Text == "X Axis").First();
xAxis.Min = 50;
xAxis.Max = 100;
xAxis.Configure();
}
Am I missing something ?
Use ILPlotCube.Limits instead:
var pc = ilPanel1.Scene.First<ILPlotCube>();
pc.Limits.Set(
new Vector3(50, pc.Limits.YMin, pc.Limits.ZMin),
new Vector3(100, pc.Limits.YMax, pc.Limits.ZMax));
BTW: the axes are accessed much easier: plotcube.Axes.XAxis ...

How to rotate image automatically in Matlab?

Currently, i'm working on an offline signature verification. So, what i want to do now is to find the specific value of rotation for that particular signature image. In this case, i want to normalize the baseline of the signature along with the horizontal axis:
.
I've tried to do some coding,
v1(1) = column2 - column1;
v1(2) = row2 - row1;
v2(1) = column2 - column1;
v2(2) = row1 - row1;
x1 = v1(1);
y1 = v1(2);
x2 = v2(1);
y2 = v2(2);
dotproduct = (x1*x2 + y1*y2);
v1mag = sqrt(x1*x1 + y1*y1);
v2mag = sqrt(x2*x2 + y2*y2);
costheta = dotproduct/(v1mag*v2mag);
angle = acos(costheta);
angleDeg = rad2deg(angle);
angleDeg = uint8(angleDeg);
angleDeg
%B = imrotate(invImg,-(angleDeg),'bilinear');
As you can see from the coding, variable 'angleDeg' holds the value of rotation angle. Before, I've used imrotate() MATLAB but the problem is that I must input the value of the angle manually instead of calling the variable of 'angleDeg'. Is there any other method/algorithm to rotate an image by calling the variable that holds the angle value beside imrotate()?
Why do you need to input the angle manually? Why do you cast angleDeg to uint8?
By the way, the function regionprops can give you the 'Orientation' of the connected component in a binary image, i. e. the angle between the major axis of the component and the horizontal.