How to draw oblique hemisphere along a certain volume? - c++

What I am trying to do:
Make an empty 3D image (.dcm in this case) with image direction as
[1,0,0;
0,1,0;
0,0,1].
In this image, I insert an oblique trajectory, which essentially represents a cuboid. Now I wish to insert a hollow hemisphere in this cuboid (cuboid with all white pixels - constant value, hemisphere can be anything but differentiable), so that it is aligned along the axis of the trajectory.
What I am getting
So I used the general formula for a sphere:
x = x0 + r*cos(theta)*sin(alpha)
y = y0 + r*sin(theta)*sin(alpha)
z = z0 + r*cos(alpha)
where, 0 <= theta <= 2 * pi, 0 <= alpha <= pi / 2, for hemisphere.
What I tried to achieve this
So first I thought to just get the rotation matrix, between the image coordinate system and the trajectory coordinate system and multiply all points on the sphere with it. This didn't give me desired results as the rotated sphere was scaled and translated. I don't get why this was happening as I checked the points myself.
Then I thought why not make a hemisphere out of a sphere, which is cut at by a plane lying parallel to the y,z plane of the trajectory coordinate system. For this, I calculated the angle between x,y and z axes of the image with that of the trajectory. Then, I started to get hemisphere coordinates for theta_rotated and alpha_rotated. This didn't work either as instead of a hemisphere, I was getting a rather weird sphere.
This is without any transformations
This is with the angle transformation (second try)
For reference,
The trajectory coordinate system :
[-0.4744, -0.0358506, -0.8553;
-0.7049, 0.613244, 0.3892;
-0.5273, -0.787537, 0.342;];
which gives angles:
x_axis angle 2.06508 pi
y_axis angle 2.2319 pi
z_axis angle 1.22175 pi
Code to generate the cuboid
Vector3d getTrajectoryPoints(std::vector<Vector3d> &trajectoryPoints, Vector3d &target1, Vector3d &tangent1){
double distanceFromTarget = 10;
int targetShift = 4;
target -= z_vector;
target -= (tangent * targetShift);
Vector3d vector_x = -tangent;
y_vector = z_vector.cross(vector_x);
target -= y_vector;
Vector3d start = target - vector_x * distanceFromTarget;
std::cout << "target = " << target << "start = " << start << std::endl;
std::cout << "x " << vector_x << " y " << y_vector << " z " << z_vector << std::endl;
double height = 0.4;
while (height <= 1.6)
{
double width = 0.4;
while (width <= 1.6){
distanceFromTarget = 10;
while (distanceFromTarget >= 0){
Vector3d point = target + tangent * distanceFromTarget;
//std::cout << (point + (z_vector*height) - (y_vector * width)) << std::endl;
trajectoryPoints.push_back(point + (z_vector * height) + (y_vector * width));
distanceFromTarget -= 0.09;
}
width += 0.09;
}
height += 0.09;
}
}
The height and width as incremented with respect to voxel spacing.
Do you guys know how to achieve this and what am I doing wrong? Kindly let me know if you need any other info.
EDIT 1
After the answer from #Dzenan, I tried the following:
target = { -14.0783, -109.8260, -136.2490 }, tangent = { 0.4744, 0.7049, 0.5273 };
typedef itk::Euler3DTransform<double> TransformType;
TransformType::Pointer transform = TransformType::New();
double centerForTransformation[3];
const double pi = std::acos(-1);
try{
transform->SetRotation(2.0658*pi, 1.22175*pi, 2.2319*pi);
// transform->SetMatrix(transformMatrix);
}
catch (itk::ExceptionObject &excp){
std::cout << "Exception caught ! " << excp << std::endl;
transform->SetIdentity();
}
transform->SetCenter(centerForTransformation);
Then I loop over all the points in the hemisphere and transform them using,
point = transform->TransformPoint(point);
Although, I'd prefer to give the matrix which is equal to the trajectory coordinate system (mentioned above), the matrix isn't orthogonal and itk wouldn't take it. It must be said that I used the same matrix for resampling this image and extracting the cuboid and this was fine. Thence, I found the angles between x_image - x_trajectory, y_image - y_trajectory and z_image - z_trajectory and used SetRotation instead which gives me the following result (still incorrect):
EDIT 2
I tried to get the sphere coordinates without actually using the polar coordinates. Following discussion with #jodag, this is what I came up with:
Vector3d center = { -14.0783, -109.8260, -136.2490 };
height = 0.4;
while (height <= 1.6)
{
double width = 0.4;
while (width <= 1.6){
distanceFromTarget = 5;
while (distanceFromTarget >= 0){
// Make sure the point lies along the cuboid direction vectors
Vector3d point = center + tangent * distanceFromTarget + (z_vector * height) + (y_vector * width);
double x = std::sqrt((point[0] - center[0]) * (point[0] - center[0]) + (point[1] - center[1]) * (point[1] - center[1]) + (point[2] - center[2]) * (point[2] - center[2]));
if ((x <= 0.5) && (point[2] >= -136.2490 ))
orientation.push_back(point);
distanceFromTarget -= 0.09;
}
width += 0.09;
}
height += 0.09;
}
But this doesn't seem to work either.
This is the output

I'm a little confused about your first plot because it appears that the points being displayed are not defined in the image coordinates. The example I'm posting below assumes that voxels must be part of the image coordinate system.
The code below transforms the voxel coordinates in the image space into the trajectory space by using an inverse transformation. It then rasterises a 2x2x2 cube centered around 0,0,0 and a 0.9 radius hemisphere sliced along the xy axis.
Rather than continuing a long discussion in the comments I've decided to post this. Please comment if you're looking for something different.
% define trajectory coordinate matrix
R = [-0.4744, -0.0358506, -0.8553;
-0.7049, 0.613244, 0.3892;
-0.5273, -0.787537, 0.342]
% initialize 50x50x50 3d image
[x,y,z] = meshgrid(linspace(-2,2,50));
sz = size(x);
x = reshape(x,1,[]);
y = reshape(y,1,[]);
z = reshape(z,1,[]);
r = ones(size(x));
g = ones(size(x));
b = ones(size(x));
blue = [0,1,0];
green = [0,0,1];
% transform image coordinates to trajectory coordinates
vtraj = R\[x;y;z];
xtraj = vtraj(1,:);
ytraj = vtraj(2,:);
ztraj = vtraj(3,:);
% rasterize 2x2x2 cube in trajectory coordinates
idx = (xtraj <= 1 & xtraj >= -1 & ytraj <= 1 & ytraj >= -1 & ztraj <= 1 & ztraj >= -1);
r(idx) = blue(1);
g(idx) = blue(2);
b(idx) = blue(3);
% rasterize radius 0.9 hemisphere in trajectory coordinates
idx = (sqrt(xtraj.^2 + ytraj.^2 + ztraj.^2) <= 0.9) & (ztraj >= 0);
r(idx) = green(1);
g(idx) = green(2);
b(idx) = green(3);
% plot just the blue and green voxels
green_idx = (r == green(1) & g == green(2) & b == green(3));
blue_idx = (r == blue(1) & g == blue(2) & b == blue(3));
figure(1); clf(1);
plot3(x(green_idx),y(green_idx),z(green_idx),' *g')
hold('on');
plot3(x(blue_idx),y(blue_idx),z(blue_idx),' *b')
axis([1,100,1,100,1,100]);
axis('equal');
axis('vis3d');

You can generate you hemisphere in some physical space, then transform it (translate and rotate) by using e.g. RigidTransform's TransformPoint method. Then use TransformPhysicalPointToIndex method in itk::Image. Finally, use SetPixel method to change intensity. Using this approach you will have to control the resolution of your hemisphere to fully cover all the voxels in the image.
Alternative approach is to construct a new image into which you create you hemisphere, then use resample filter to create a transformed version of the hemisphere in an arbitrary image.

Related

How to determine the axis of rotation from a set of point clouds

I have a number of point clouds taken from an kinect-like instrument that is mounted on a tripod and then rotated. How do I determine the rotation axis accurately? I'm using c++ PCL and Eigen.
I can match the point clouds together with ICP and run a global registration (SLAM or ELCH) to get combined point cloud but for a number of reasons I would like to be able to determine the axis accurately and force the registrations to respect this rotation.
One issue that is related to this problem is the origin of my instrument. I can measure the distance to the rotation axis from the external dimensions of the device fairly accurately but I don't know exactly where is the origin in relation the extremities of the device. Solving this issue could help me to locate the origin too.
There are two methods that I'm considering.
One is to take the transformation matrices of the registered point clouds and extract the translation vectors that represent the locations where the transformation would project the internal origin in the current position. To the set of points acquired this way I could try to fit a circle and the center point would represent a vector from the origin to the rotation axis and the normal direction of the circle would be the direction of the axis.
The other option is to determine the rotation axis directly from any single rotation matrix, but the vector to the rotation axis seems volatile.
Any better solutions or insights on the issue?
You need to calculate the major axis oft the tensor of inertia. https://en.m.wikipedia.org/wiki/Moment_of_inertia.
All points can be considered to have the same mass. Then you can use the Steiner approach.
THIS IS NOT AN ANSWER TO THE ORIGINAL QUESTION BUT CLARIFICATION TO A DISCUSSION ABOUT DEFINING THE ROTATION AXIS BETWEEN TWO POSES
Deepfreeze. Here is an Octave script to demonstrate what we discussed in the chat. I know it might be bad practice to post an answer when not presenting one, but I hope this will give you an insight on what I was trying to explain about the relationship between the translation vector and the point on the rotation axis (t_i in your notation).
rotation_axis_unit = [0,0,1]' % parallel to z axis
angle = 1 /180 *pi() % one degree
% a rotaion matrix of one degree rotation
R = [cos(angle) -sin(angle) 0 ; sin(angle) cos(angle) 0 ; 0 0 1 ];
% the point around wich to rotate
axis_point = [-10,0,0]' % a point
% just a point used to demonstrate that all points form a circular path
test_point = [10,5,0]';
%containers for plotting
path_origin = zeros(360,3);
path_test_point = zeros(360,3);
path_v = zeros(360,3);
origin = [0,0,0]';
% updating rotation matrix
R_i = R;
M1 = [R,R*-axis_point.+axis_point;[0,0,0,1]];
% go around a full circle
for i=1:360
% v = the last column of M. Created from axis_point.
% -axis_point is the vector from axis_point to origin which is being rotated
% then a correction is applied to center it around the axis point
v = R_i * -axis_point .+ axis_point;
% building 4x4 transformation matrix
M = [R_i, v;[0,0,0,1]];
% M could also be built M_i = M1 * M_i, rotating the previous M by one degree around axis_point
% rotatin testing point and saving it
test_point_i = M * [test_point;1];
path_test_point(i,:) = test_point_i(1:3,1)';
% saving the translation part of M
path_v(i,:) = v';
% rotating origin point and saving it
origin_i = test_point_i = M * [origin;1];
path_origin(i,:) = origin_i(1:3,1)';
R_i = R * R_i ;
end
figure(1)
% plot test point path, just to show it forms a circular path, center and axis_point
scatter3(path_test_point(:,1), path_test_point(:,2), path_test_point(:,3), 5,'r')
hold on
% plotting origin path, circular, center at axis_point
scatter3(path_origin(:,1), path_origin(:,2), path_origin(:,3), 7,'r')
hold on
% plotting translation vectors, identical to origin path, (if invisible rotate so that you are watching it from z axis direction)
scatter3(path_v(:,1), path_v(:,2), path_v(:,3), 1, 'black');
hold on
% plots for visual analysis
scatter3(0,0,0,5,'b') % origin
hold on
scatter3(axis_point(1), axis_point(2), axis_point(3), 5, 'g') % axis point, center of the circles
hold on
scatter3(test_point(1), test_point(2), test_point(3), 5, 'black') % test point origin
hold off
% what does this demonstrate?
% it shows that that the ralationship between a 4x4
% transformation matrix and axis_angle notation plus point on the rotation axis
% M = [ R, v,; [0,0,0,1]] = [ R_i , R_i * -c + c; [ 0, 0, 0, 1] ]
%
% where c equals axis_point ( = perpendicular vector from origin to the axis of rotation )
% pay attention to path_v and path_origin
% they are identical
% path_v was extracted from the 4x4 transformation matrix M
% and path_origin was created by rotating the origin point by M
%--> v = R_i * -.c +.c
% Notice that since M describes a rotation of alpha angles around an
% axis that goes through c
% and its translation vector lies on a circle whose center
% is at the rotation_axis and radius is the distance from that
% point to origin ->
%
% M * M will describe a rotation of 2 x alpha angles around the same axis
% Therefore you can easily create more points that lay on that circle
% by multiplying M by itself and extracting the translation vector
%
% c can then be solved by normal circle fit algorithms.
%------------------------------------------------------------
% CAUTION !!!
% this applies perfectly when the transformation matrices have been created so
% that the translation is perfectly orthogonal to the rotation axis
% in real world matrices the translation will not be orthogonal
% therefore the points will not travel on a circular path but on a helix and this needs to be
% dealt with when solving the center of rotation.
An option is to place a chessboard at ~1 [m]. Use the kinect camera to make images for different rotations, where the hole chessboard is still visible. Fit the chessboard using OpenCV.
The goal is to find the xyz coordinates of the chessboard for the different orientations. Use your camera api functions to determine the xyz coordinates of the chessboard or do the following:
Determine camera intrinsics of camera 1 and 2. (use both color and IR images for kinect).
Determine camera extrinsics (camera 2 [R,t] wrt camera 1)
Use the values to calculate projection matrices
Use the projection matrices to triangulate the points of the chessboard to get coordinates in [X,Y,Z] wrt camera1 coordinate system.
Each group of chessboard points is called [x_i]. Now we can write the equation:
Update:
This equation can be solved with a non-linear solver, I used ceres-solver.
#include "ceres/ceres.h"
#include "ceres/rotation.h"
#include "glog/logging.h"
#include "opencv2/opencv.hpp"
#include "csv.h"
#include "Eigen/Eigen"
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;
struct AxisRotationError {
AxisRotationError(double observed_x0, double observed_y0, double observed_z0, double observed_x1, double observed_y1, double observed_z1)
: observed_x0(observed_x0), observed_y0(observed_y0), observed_z0(observed_z0), observed_x1(observed_x1), observed_y1(observed_y1), observed_z1(observed_z1) {}
template <typename T>
bool operator()(const T* const axis, const T* const angle, const T* const trans, T* residuals) const {
//bool operator()(const T* const axis, const T* const trans, T* residuals) const {
// Normalize axis
T a[3];
T k = axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2];
a[0] = axis[0] / sqrt(k);
a[1] = axis[1] / sqrt(k);
a[2] = axis[2] / sqrt(k);
// Define quaternion from axis and angle. Convert angle to radians
T pi = T(3.14159265359);
//T angle[1] = {T(10.0)};
T quaternion[4] = { cos((angle[0]*pi / 180.0) / 2.0),
a[0] * sin((angle[0] * pi / 180.0) / 2.0),
a[1] * sin((angle[0] * pi / 180.0) / 2.0),
a[2] * sin((angle[0] * pi / 180.0) / 2.0) };
// Define transformation
T t[3] = { trans[0], trans[1], trans[2] };
// Calculate predicted positions
T observedPoint0[3] = { T(observed_x0), T(observed_y0), T(observed_z0)};
T point[3]; point[0] = observedPoint0[0] - t[0]; point[1] = observedPoint0[1] - t[1]; point[2] = observedPoint0[2] - t[2];
T rotatedPoint[3];
ceres::QuaternionRotatePoint(quaternion, point, rotatedPoint);
T predicted_x = rotatedPoint[0] + t[0];
T predicted_y = rotatedPoint[1] + t[1];
T predicted_z = rotatedPoint[2] + t[2];
// The error is the difference between the predicted and observed position.
residuals[0] = predicted_x - T(observed_x1);
residuals[1] = predicted_y - T(observed_y1);
residuals[2] = predicted_z - T(observed_z1);
return true;
}
// Factory to hide the construction of the CostFunction object from
// the client code.
static ceres::CostFunction* Create(const double observed_x0, const double observed_y0, const double observed_z0,
const double observed_x1, const double observed_y1, const double observed_z1) {
// Define AutoDiffCostFunction. <AxisRotationError, #residuals, #dim axis, #dim angle, #dim trans
return (new ceres::AutoDiffCostFunction<AxisRotationError, 3, 3, 1,3>(
new AxisRotationError(observed_x0, observed_y0, observed_z0, observed_x1, observed_y1, observed_z1)));
}
double observed_x0;
double observed_y0;
double observed_z0;
double observed_x1;
double observed_y1;
double observed_z1;
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
// Load points.csv into cv::Mat's
// 216 rows with (x0, y0, z0, x1, y1, z1)
// [x1,y1,z1] = R* [x0-tx,y0-ty,z0-tz] + [tx,ty,tz]
// The xyz coordinates are points on a chessboard, where the chessboard
// is rotated for 4x. Each chessboard has 54 xyz points. So 4x 54,
// gives the 216 rows of observations.
// The chessboard is located at [0,0,1], as the camera_0 is located
// at [-0.1,0,0], the t should become [0.1,0,1.0].
// The chessboard is rotated around axis [0.0,1.0,0.0]
io::CSVReader<6> in("points.csv");
float x0, y0, z0, x1, y1, z1;
// The observations
cv::Mat x_0(216, 3, CV_32F);
cv::Mat x_1(216, 3, CV_32F);
for (int rowNr = 0; rowNr < 216; rowNr++){
if (in.read_row(x0, y0, z0, x1, y1, z1))
{
x_0.at<float>(rowNr, 0) = x0;
x_0.at<float>(rowNr, 1) = y0;
x_0.at<float>(rowNr, 2) = z0;
x_1.at<float>(rowNr, 0) = x1;
x_1.at<float>(rowNr, 1) = y1;
x_1.at<float>(rowNr, 2) = z1;
}
}
std::cout << x_0(cv::Rect(0, 0, 2, 5)) << std::endl;
// The variable to solve for with its initial value. It will be
// mutated in place by the solver.
int numObservations = 216;
double axis[3] = { 0.0, 1.0, 0.0 };
double* pAxis; pAxis = axis;
double angles[4] = { 10.0, 10.0, 10.0, 10.0 };
double* pAngles; pAngles = angles;
double t[3] = { 0.0, 0.0, 1.0,};
double* pT; pT = t;
bool FLAGS_robustify = true;
// Build the problem.
Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
for (int i = 0; i < numObservations; ++i) {
ceres::CostFunction* cost_function =
AxisRotationError::Create(
x_0.at<float>(i, 0), x_0.at<float>(i, 1), x_0.at<float>(i, 2),
x_1.at<float>(i, 0), x_1.at<float>(i, 1), x_1.at<float>(i, 2));
//std::cout << "pAngles: " << pAngles[i / 54] << ", " << i / 54 << std::endl;
ceres::LossFunction* loss_function = FLAGS_robustify ? new ceres::HuberLoss(0.001) : NULL;
//ceres::LossFunction* loss_function = FLAGS_robustify ? new ceres::CauchyLoss(0.002) : NULL;
problem.AddResidualBlock(cost_function, loss_function, pAxis, &pAngles[i/54], pT);
//problem.AddResidualBlock(cost_function, loss_function, pAxis, pT);
}
// Run the solver!
ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_SCHUR;
//options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
options.num_threads = 4;
options.use_nonmonotonic_steps = false;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
//std::cout << summary.FullReport() << "\n";
std::cout << summary.BriefReport() << "\n";
// Normalize axis
double k = axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2];
axis[0] = axis[0] / sqrt(k);
axis[1] = axis[1] / sqrt(k);
axis[2] = axis[2] / sqrt(k);
// Plot results
std::cout << "axis: [ " << axis[0] << "," << axis[1] << "," << axis[2] << " ]" << std::endl;
std::cout << "t: [ " << t[0] << "," << t[1] << "," << t[2] << " ]" << std::endl;
std::cout << "angles: [ " << angles[0] << "," << angles[1] << "," << angles[2] << "," << angles[3] << " ]" << std::endl;
return 0;
}
The result I've got:
iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
0 3.632073e-003 0.00e+000 3.76e-002 0.00e+000 0.00e+000 1.00e+004 0 4.30e-004 7.57e-004
1 3.787837e-005 3.59e-003 2.10e-003 1.17e-001 1.92e+000 3.00e+004 1 7.43e-004 8.55e-003
2 3.756202e-005 3.16e-007 1.73e-003 5.49e-001 1.61e-001 2.29e+004 1 5.35e-004 1.13e-002
3 3.589147e-005 1.67e-006 2.90e-004 9.19e-002 9.77e-001 6.87e+004 1 5.96e-004 1.46e-002
4 3.584281e-005 4.87e-008 1.38e-005 2.70e-002 1.00e+000 2.06e+005 1 4.99e-004 1.73e-002
5 3.584268e-005 1.35e-010 1.02e-007 1.63e-003 1.01e+000 6.18e+005 1 6.32e-004 2.01e-002
Ceres Solver Report: Iterations: 6, Initial cost: 3.632073e-003, Final cost: 3.584268e-005, Termination: CONVERGENCE
axis: [ 0.00119037,0.999908,-0.0134817 ]
t: [ 0.0993185,-0.0080394,1.00236 ]
angles: [ 9.90614,9.94415,9.93216,10.1119 ]
The angles result is quite nice 10 degrees. These can even be fixed for my case, as I know the rotation very accurately from my rotation stage. There is a small difference in the t and axis. This is cause by inaccuracies in my virtual stereoCamera simulation. My chessboard squares are not exactly square and the dimensions are also a little off....
My simulation scripts, images, results: blender_simulation.zip

Transform images with bezier curves

I'm using this article: nonlingr as a font to understand non linear transformations, in the section GLYPHS ALONG A PATH he explains how to use a parametric curve to transform an image, i'm trying to apply a cubic bezier to an image, however i have been unsuccessfull, this is my code:
OUT.aloc(IN.width(), IN.height());
//get the control points...
wVector p0(values[vindex], values[vindex+1], 1);
wVector p1(values[vindex+2], values[vindex+3], 1);
wVector p2(values[vindex+4], values[vindex+5], 1);
wVector p3(values[vindex+6], values[vindex+7], 1);
//this is to calculate t based on x
double trange = 1 / (OUT.width()-1);
//curve coefficients
double A = (-p0[0] + 3*p1[0] - 3*p2[0] + p3[0]);
double B = (3*p0[0] - 6*p1[0] + 3*p2[0]);
double C = (-3*p0[0] + 3*p1[0]);
double D = p0[0];
double E = (-p0[1] + 3*p1[1] - 3*p2[1] + p3[1]);
double F = (3*p0[1] - 6*p1[1] + 3*p2[1]);
double G = (-3*p0[1] + 3*p1[1]);
double H = p0[1];
//apply the transformation
for(long i = 0; i < OUT.height(); i++){
for(long j = 0; j < OUT.width(); j++){
//t = x / width
double t = trange * j;
//apply the article given formulas
double x_path_d = 3*t*t*A + 2*t*B + C;
double y_path_d = 3*t*t*E + 2*t*F + G;
double angle = 3.14159265/2.0 + std::atan(y_path_d / x_path_d);
mapped_point.Set((t*t*t)*A + (t*t)*B + t*C + D + i*std::cos(angle),
(t*t*t)*E + (t*t)*F + t*G + H + i*std::sin(angle),
1);
//test if the point is inside the image
if(mapped_point[0] < 0 ||
mapped_point[0] >= OUT.width() ||
mapped_point[1] < 0 ||
mapped_point[1] >= IN.height())
continue;
OUT.setPixel(
long(mapped_point[0]),
long(mapped_point[1]),
IN.getPixel(j, i));
}
}
Applying this code in a 300x196 rgb image all i get is a black screen no matter what control points i use, is hard to find information about this kind of transformation, searching for parametric curves all i find is how to draw them, not apply to images. Can someone help me on how to transform an image with a bezier curve?
IMHO applying a curve to an image sound like using a LUT. So you will need to check for the value of the curve for different image values and then switch the image value with the one on the curve, so, create a Look-Up-Table for each possible value in the image (e.g : 0, 1, ..., 255, for a gray value 8 bit image), that is a 2x256 matrix, first column has the values from 0 to 255 and the second one having the value of the curve.

Show more points then resolution

I am drawing a graph with 2000+ points to a pdf file. The resolution of the pdf is 612 x 792. I can only draw 612 points to the pdf because the width is 612. I am mapping 1 point to 1 pixel. How can I plot all 2000+ samples to the pdf. I am using this lib http://www.vulcanware.com/cpp_pdf/index.html.
Option 1: Scale the points, using x = (x * 612) / 2000. This will mean that if 2 points are close to each other (including "similar y") they will overwrite each other.
Option 2: Treat each point as a square; and calculate floating point values for the "left edge x" and "right edge x" that have been scaled (left_x = ( (x-width/2.0) * 612.0) / 2000.0; right_x = ( (x+width/2.0) * 612.0) / 2000.0;), and draw the square using anti-aliasing, by calculating "area of destination pixel that the square overlaps" for each destination pixel that overlaps with the square. In this case you will need to do "dest_pixel = max(dest_pixel + area, 1);" to clamp pixel values when squares overlap.
Option 3: Rotate the whole thing 90 degrees so that "x axis" goes vertically down the page (and can be split across multiple pages if necessary); and if this causes a problem for y then use one of the options above for y.
Note that "option 2" can be done in both (vertical and horizontal) directions at the same time. To do this, start by determining the edges of the square, like:
left_x = point_x / MAX_SRC_X * MAX_DEST_X;
right_x = (point_x + 1) / MAX_SRC_X * MAX_DEST_X;
top_y = point_y / MAX_SRC_Y * MAX_DEST_Y;
bottom_y = (point_y + 1) / MAX_SRC_Y * MAX_DEST_Y;
Then have a "for each row that is effected" loop that calculates how much each row is effected, like:
for(int y = top_y; y < bottom_y; y++) {
row_top = fmax(y, top_y);
row_bottom = fmin(y+1, bottom_y);
row_weight = row_bottom - row_top;
Then have a similar "for each column that is effected" loop, like:
for(int x = left_x; x < right_x; x++) {
column_left = fmax(x, left_x);
column_right = fmin(x+1, right_x);
column_weight = column_right - column_left;
Then calculate the area for the pixel, set the pixel, and complete the loops:
dest_pixel_area = row_weight * column_weight;
pixel[y][x].red = min(pixel[y][x].red + dest_pixel_area * red, MAX_RED);
pixel[y][x].green = min(pixel[y][x].green + dest_pixel_area * green, MAX_GREEN);
pixel[y][x].blue = min(pixel[y][x].blue + dest_pixel_area * blue, MAX_BLUE);
}
}
Note: All code above is untested and simplified. It can be faster to break the loops up into "first line/column; loop for middle area only; then last line/column" to remove most of the fmin/fmax.
If you only need to do this in one direction, delete the parts for the direction you don't need and use 1.0 for the corresponding row_weight or column_weight.

Ray Tracing - Geometric Sphere Intersection - Intersection function returns true for all rays despite no intersection

I am writing a ray tracing project with C++ and OpenGL and am running into some obstacles with my sphere intersection function: I've checked multiple sources and the math looks right, but for some reason for every single ray, the intersection method is returning true. Here is the code to the sphere intersection function as well as some other code for clarification:
bool intersect(Vertex & origin, Vertex & rayDirection, float intersection)
{
bool insideSphere = false;
Vertex oc = position - origin;
float tca = 0.0;
float thcSquared = 0.0;
if (oc.length() < radius)
insideSphere = true;
tca = oc.dot(rayDirection);
if (tca < 0 && !insideSphere)
return false;
thcSquared = pow(radius, 2) - pow(oc.length(), 2) + pow(tca, 2);
if (thcSquared < 0)
return false;
insideSphere ? intersection = tca + sqrt(thcSquared) : intersection = tca - sqrt(thcSquared);
return true;
}
Here is some context from the ray tracing function that calls the intersection function. FYI my camera is at (0, 0, 0) and that is what is in my "origin" variable in the ray tracing function:
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define WINDOW_METERS_WIDTH 30
#define WINDOW_METERS_HEIGHT 20
#define FOCAL_LENGTH 25
rayDirection.z = FOCAL_LENGTH * -1;
for (int r = 0; r < WINDOW_HEIGHT; r++)
{
rayDirection.y = (WINDOW_METERS_HEIGHT / 2 * -1) + (r * ((float)WINDOW_METERS_HEIGHT / (float)WINDOW_HEIGHT));
for (int c = 0; c < WINDOW_WIDTH; c++)
{
intersection = false;
t = 0.0;
rayDirection.x = (WINDOW_METERS_WIDTH / 2 * -1) + (c * ((float)WINDOW_METERS_WIDTH / (float)WINDOW_WIDTH));
rayDirection = rayDirection - origin;
for (int i = 0; i < NUM_SPHERES; i++)
{
if (spheres[i].intersect(CAM_POS, rayDirection, t))
{
intersection = true;
}
}
Thanks for taking a look and let me know if there is any other code that may help!
It seems you got your math a bit mixed. The first part of the function, ie until the first return false, is ok and will return false if the ray start outside of the sphere and don't go toward it. However, I think you put the camera outside all your spheres in such a manner that all spheres are visible, that's why this part never return false.
thcSquared is really wrong and I don't know what it is supposed to represent.
Let's do the intersection mathematically. We have:
origin : the start of the ray, let's call this A
rayDirection : the direction of the infinite ray, let's call this d.
position : the center of the sphere, called P
radius : self-explanatory, called r
What you want is a point on both the sphere and the line, let's call it M:
M = A + t * d because it is on the line
|M - P| = r because it is on the sphere
The second equation can be changed to be |A + t * d - P|² = r², which gives (A - P)² + 2 * t * (A - P).dot(d) + t²d² = r². This is a simple quadratic equation. Once solved, you have 0, 1 or 2 solutions, select the closest to the ray origin (but which is positive).
edit: You are forced to use another approach that I will detail here:
Compute the distance between the center of the sphere and the line (calling it l). This is done by 'projecting' the center on the line. So:
tca = ( (P - A) dot d ) / |d|, or with your variable names, tca = (OC dot rd) / |rd|. The projection is H = A + tca * d, and l = |H - P|.
If l > R then return false, there is no intersection.
Let's call M one intersection point. The triangle MHP have a right angle, so MH² + HP² = MP², in other terms thc² + l² = r², so we now have thc, the distance from H to the sphere.
With all that, t = tca +- thc, simply take the lowest non-negative of the two.
The paper you linked explain this, but without saying that it assumes the norm of the ray direction to be 1. I don't see a normalization in your code, that may be why your code fails (not verified).
Side note: the name Vertex for a 3d vector is really badly chosen, something like Vector3 or vec3 would be way better.

How to find the angle of rotation and translation using opencv if I know the homogeneous transformation matrix in 3d?

I found several post about this subject, but none of the solutions are using opencv.
I am wondering if OpenCv has any function, or class that could help on this subject?
I have a 4*4 affine transformation in opencv and I am looking to find the rotation, translation assuming that scaling is 1 and there is no other transformation in matrix.
Is there any function in OpenCV to help finding these parameters?
The problem you're facing is known as a matrix decomposition problem.
You can retrieve your desired matrices following these steps:
Compute the scaling factors as the magnitudes of the first three basis vectors (columns or rows) of the matrix
Divide the first three basis vectors by these values (thus normalizing them)
The upper-left 3x3 part of the matrix now represents the rotation (you can use this as is, or convert it to quaternion form)
The translation is the fourth basis vector of the matrix (in homogeneous coordinates - it'll be the first three elements that you're interested in)
In your case, being your scaling factor 1, you can skip the first two steps.
To retrieve the rotation matrix axis and angle (in radians) I suggest you to port the following Java algorithm in OpenCV (source: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/).
/**
This requires a pure rotation matrix 'm' as input.
*/
public axisAngle toAxisAngle(matrix m) {
double angle,x,y,z; // variables for result
double epsilon = 0.01; // margin to allow for rounding errors
double epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
// optional check that input is pure rotation, 'isRotationMatrix' is defined at:
// http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
assert isRotationMatrix(m) : "not valid rotation matrix" ;// for debugging
if ((Math.abs(m[0][1]-m[1][0])< epsilon)
&& (Math.abs(m[0][2]-m[2][0])< epsilon)
&& (Math.abs(m[1][2]-m[2][1])< epsilon)) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonaland zero in other terms
if ((Math.abs(m[0][1]+m[1][0]) < epsilon2)
&& (Math.abs(m[0][2]+m[2][0]) < epsilon2)
&& (Math.abs(m[1][2]+m[2][1]) < epsilon2)
&& (Math.abs(m[0][0]+m[1][1]+m[2][2]-3) < epsilon2)) {
// this singularity is identity matrix so angle = 0
return new axisAngle(0,1,0,0); // zero angle, arbitrary axis
}
// otherwise this singularity is angle = 180
angle = Math.PI;
double xx = (m[0][0]+1)/2;
double yy = (m[1][1]+1)/2;
double zz = (m[2][2]+1)/2;
double xy = (m[0][1]+m[1][0])/4;
double xz = (m[0][2]+m[2][0])/4;
double yz = (m[1][2]+m[2][1])/4;
if ((xx > yy) && (xx > zz)) { // m[0][0] is the largest diagonal term
if (xx< epsilon) {
x = 0;
y = 0.7071;
z = 0.7071;
} else {
x = Math.sqrt(xx);
y = xy/x;
z = xz/x;
}
} else if (yy > zz) { // m[1][1] is the largest diagonal term
if (yy< epsilon) {
x = 0.7071;
y = 0;
z = 0.7071;
} else {
y = Math.sqrt(yy);
x = xy/y;
z = yz/y;
}
} else { // m[2][2] is the largest diagonal term so base result on this
if (zz< epsilon) {
x = 0.7071;
y = 0.7071;
z = 0;
} else {
z = Math.sqrt(zz);
x = xz/z;
y = yz/z;
}
}
return new axisAngle(angle,x,y,z); // return 180 deg rotation
}
// as we have reached here there are no singularities so we can handle normally
double s = Math.sqrt((m[2][1] - m[1][2])*(m[2][1] - m[1][2])
+(m[0][2] - m[2][0])*(m[0][2] - m[2][0])
+(m[1][0] - m[0][1])*(m[1][0] - m[0][1])); // used to normalise
if (Math.abs(s) < 0.001) s=1;
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
angle = Math.acos(( m[0][0] + m[1][1] + m[2][2] - 1)/2);
x = (m[2][1] - m[1][2])/s;
y = (m[0][2] - m[2][0])/s;
z = (m[1][0] - m[0][1])/s;
return new axisAngle(angle,x,y,z);
}