Get depth from camera for each pixel - c++

I have a mesh model and, using VTK, have rendered a view of it from a given camera position (x,y,z). I can save this to an RGB image (640x480) but I also want to save a depth map where each pixel stores the value of the depth from the camera.
I have tried using the Zbuffer values given by the render window by following this example. The problem is that the Zbufer only stores values in the range [0,1]. Instead I am trying to create synthetic range image, where I store the depth/distance of each pixel from the camera. Analogous to the image produced by the Kinect, I am trying to create one from a specific viewpoint of a mesh model.
EDIT - adding some code
My current code:
Load the mesh
string mesh_filename = "mesh.ply";
vtkSmartPointer<vtkPLYReader> mesh_reader = read_mesh_ply(mesh_filename);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(mesh_reader->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//Add the actors to the scene
renderer->AddActor(actor);
renderer->SetBackground(1, 1, 1);
Create a camera and place it somewhere
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
renderer->SetActiveCamera(camera);
camera->SetPosition(0,0,650);
//Render and interact
renderWindow->Render();
Get result from the z buffer
double b = renderer->GetZ(320, 240);
In this example, this gives 0.999995. As the values are between [0,1] I don't know how to interpret this, as you can see I have set the camera to be 650 units away on the z-axis so I assume the z distance at this pixel (which is on the object in the rendered RGB) should be near to 650.

This python snippet illustrates how to convert z buffer values to real distances. The non-linear mapping is defined as follows:
numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator
Here, a full example:
import vtk
import numpy as np
from vtk.util import numpy_support
import matplotlib.pyplot as plt
vtk_renderer = vtk.vtkRenderer()
vtk_render_window = vtk.vtkRenderWindow()
vtk_render_window.AddRenderer(vtk_renderer)
vtk_render_window_interactor = vtk.vtkRenderWindowInteractor()
vtk_render_window_interactor.SetRenderWindow(vtk_render_window)
vtk_render_window_interactor.Initialize()
source = vtk.vtkCubeSource()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(source.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.RotateX(60.0)
actor.RotateY(-35.0)
vtk_renderer.AddActor(actor)
vtk_render_window.Render()
active_vtk_camera = vtk_renderer.GetActiveCamera()
z_near, z_far = active_vtk_camera.GetClippingRange()
z_buffer_data = vtk.vtkFloatArray()
width, height = vtk_render_window.GetSize()
vtk_render_window.GetZbufferData(
0, 0, width - 1, height - 1, z_buffer_data)
z_buffer_data_numpy = numpy_support.vtk_to_numpy(z_buffer_data)
z_buffer_data_numpy = np.reshape(z_buffer_data_numpy, (-1, width))
z_buffer_data_numpy = np.flipud(z_buffer_data_numpy) # flipping along the first axis (y)
numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator
non_depth_data_value = np.nan
depth_buffer_data_numpy[z_buffer_data_numpy == 1.0] = non_depth_data_value
print(np.nanmin(depth_buffer_data_numpy))
print(np.nanmax(depth_buffer_data_numpy))
plt.imshow(np.asarray(depth_buffer_data_numpy))
plt.show()
Side note:
On my system, a few times the imshow command did not display anything. Re-running the script did solve that issue.
Sources:
http://web.archive.org
open3d

Related

Getting absolute rectangle coordinates after direct2d translation and scale

I'm using direct2d to draw a bitmap (play a video) in a window, and I want to get the absolute coordinates for any position in the playing space, whether transformations are applied or not. So if the resolution is 1280x720, then by hovering the cursor over the image, I should get values like x = 0 ... 1280, y = 0 ... 720.
The positions of the total video area are in the variable m_rcLiveWindowPos, while the variable m_rcDstVideoRect contains the positions of the actual video after adjusting for the aspect ratio. Finally, m_rcSrcVideoRect is just the video resolution (ex: left=0, top=0, right=1280, bottom=720).
Below, I applied a translation and then a scale to the renderTarget. The rawScaleFactor is a number representing the amount to scale the video: if rawScaleFactor=1, then the video should be played at 100%. If 2, then at 200%.
This all works great -- the video zooms in properly and I can click and drag the video around. The problem is that I want to get the absolute x and y coordinates of the video resolution while my cursor is hovering over the video. The first definitions of mousePosInImage work for videos with no zoom/panning with the m_rcDstVideoRect sitting in a "fitted" position, but the values are incorrect for a zoomed-in video.
if (rawScaleFactor != 0)
{
// Make the dragging more precise based on the scaling factor.
float dragPosX = (float)m_rawScaleOffsetX / (rawScaleFactor * 2.0f);
float dragPosY = (float)m_rawScaleOffsetY / (rawScaleFactor * 2.0f);
D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(dragPosX, dragPosY);
// Get the center point of the current image.
float centerPointX = float(m_rcLiveWindowPos.Width()) / 2;
float centerPointY = float(m_rcLiveWindowPos.Height()) / 2;
// Calculate the amount that the image must scaled by.
D2D1ScaleFactor = ((float)m_videoResolution.width / (float)(m_rcDstVideoRect.right - m_rcDstVideoRect.left)) * (float)rawScaleFactor;
D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale(D2D1::Size(D2D1ScaleFactor, D2D1ScaleFactor),
D2D1::Point2F(centerPointX, centerPointY));
// First translate the image, then scale it.
m_pJRenderTarget->SetTransform(translation * scale);
int32_t width = ((int32_t)m_videoResolution.width);
int32_t height = ((int32_t)m_videoResolution.height);
// This works for non-zoomed in video:
m_mousePosInImageX = int32_t(width * (rawMousePosX - m_rcDstVideoRect.left) / (m_rcDstVideoRect.right - m_rcDstVideoRect.left));
m_mousePosInImageY = int32_t(height * (rawMousePosY - m_rcDstVideoRect.top) / (m_rcDstVideoRect.bottom - m_rcDstVideoRect.top));
// Does not work for all cases...
m_mousePosInImageX = int32_t((centerPointX * D2D1ScaleFactor) - (centerPointX) + (m_mousePosInImageX / D2D1ScaleFactor));
m_mousePosInImageY = int32_t((centerPointY * D2D1ScaleFactor) - (centerPointY) + (m_mousePosInImageY / D2D1ScaleFactor));
}
m_pJRenderTarget-> DrawBitmap(m_pJVideoBitmap,
m_rcDstVideoRect,
1.0f,
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
m_rcSrcVideoRect);
I need a way to "reflect" the changes that SetTransform() did in the mousePosInImage variables.

OpenCV drawCircle and draw Rectangles on the circle line

I want to draw circles with different radius and then I want to draw rectangles on this circle.
It should look like this:
]
I have tried it with the formula for the circle
y_Circle = Center_Circle.y + sqrt(pow(Radius, 2) - pow(x_Circle - Center_Circle.x, 2));
but this is just for the lower part of the circle. For the upper part I need this formula, but with a "-" after Center_Circly.y.
The Problem is, that i´m not getting the rectangles in the position like in the image above. It looks like this:
In this image I draw the rectangles on a circle with the formula above. For a better unterstanding I have drawn two circles by hand to show the problem.
You can see, that there is space between the rectangles and in the lower part there is no space between the rectangles. Is there another possibility to do that in an easier way? Maybe like this: Draw a circle with openCV, get access to the coordinates of the circle line and draw the rectangles of this circle line. But I don´t know how to get acces to the coordinates of the circle.
Here is my code-snippet:
for (int Radius = Rect_size; Radius < MaxRadius;)
{
x_Circle = MaxRadius - Radius;
circumference_half = 2 * 3.1415 * Radius / 2;
Rectangle_count = circumference_half / Rect_size;
for (int i = 0; i < Rectangle_count - 1; i++)
{
y_Circle = Center_Circle.y + sqrt(pow(Radius, 2) - pow(x_Circle - Center_Circle.x, 2));
if (y_Circle <= FRAME_Heigth && x_Circle <= FRAME_WIDTH && x_Circle >=0)
{
test = Rect(x_Circle, y_Circle, Rect_size, Rect_size);
rectangle(RectangePic, test, Scalar(0, 255, 255), 1, 8);
imshow("testee", RectangePic);
waitKey();
}
x_Circle += Rect_size;
}
Radius += Rect_size;
}
Try this script for these results:
import cv2, numpy as np, math
# Parameters for the window
hw = 789
# Parameters for the circle
circle_center = hw/2, hw/2
radius = hw/2.25
circle_thickness = 2
circle_color = (255,0,255)
# Parameters for the boxes
num_boxes = 50
box_size = 30
box_color = (0,255,0)
box_thickness = 2
# Create background image
bg = np.zeros((hw, hw, 3), np.uint8)
# Draw circle
cv2.circle(bg, tuple(np.array(circle_center, int)), int(radius), circle_color, circle_thickness)
# Time to draw some boxes!
for index in range(num_boxes):
# Compute the angle around the circle
angle = 2 * math.pi * index / num_boxes
# Compute the center of the box
x, y = circle_center[0] + math.sin(angle)*radius, circle_center[1] + math.cos(angle)*radius
# Compute the corners of the
pt1 = x-box_size/2, y-box_size/2
pt2 = x+box_size/2, y+box_size/2
# Draw Box
cv2.rectangle(bg, tuple(np.array(pt1, int)),tuple(np.array(pt2, int)), box_color, box_thickness)
cv2.imshow('img', bg)
cv2.waitKey(0)
cv2.destroyAllWindows()

How to rotate a vtk scene around a specific point?

I have a 3D vtk scene representing a point cloud, displayed through a QVTKWidget.
vtk7.1, Qt5.8.
I want to be able to rotate the scene around specific coordinates, but I don't know how to proceed.
I like the trackball interaction. I just need to set the center, but I'm a bit lost in VTK api.
I think I can do this by changing the rotation matrix : InvTranslation + Rotation + Translation should do the trick. I see two ways of doing it :
1)
Get the Rotation Matrix computed by VTK
Generate a new matrix
Apply the matrix.
2)
set a transform to vtk to apply before the process
set a transform to vtk to apply after the process
Am I in the right direction? If yes, how I can implement one of these solutions..?
Thank i advance,
Etienne.
Problem solved. The change of focale would also change the view. SO, I aplied a few geometric transform, and there it is.
// vtk Element /////////////////////////////////////////////////////////
vtkRenderWindowInteractor *rwi = widget->GetInteractor();
vtkRenderer *renderer = widget->GetRenderWindow()->GetRenderers()->GetFirstRenderer();
vtkCamera *camera = renderer->GetActiveCamera();
// Camera Parameters ///////////////////////////////////////////////////
double *focalPoint = camera->GetFocalPoint();
double *viewUp = camera->GetViewUp();
double *position = camera->GetPosition();
double axis[3];
axis[0] = -camera->GetViewTransformMatrix()->GetElement(0,0);
axis[1] = -camera->GetViewTransformMatrix()->GetElement(0,1);
axis[2] = -camera->GetViewTransformMatrix()->GetElement(0,2);
// Build The transformatio /////////////////////////////////////////////////
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
transform->Identity();
transform->Translate(d->center[0], d->center[1], d->center[2]);
transform->RotateWXYZ(rxf, viewUp); // Azimuth
transform->RotateWXYZ(ryf, axis); // Elevation
transform->Translate(-d->center[0], -d->center[1], -d->center[2]);
double newPosition[3];
transform->TransformPoint(position,newPosition); // Transform Position
double newFocalPoint[3];
transform->TransformPoint(focalPoint, newFocalPoint); // Transform Focal Point
camera->SetPosition(newPosition);
camera->SetFocalPoint(newFocalPoint);
// Orhthogonalize View Up //////////////////////////////////////////////////
camera->OrthogonalizeViewUp();
renderer->ResetCameraClippingRange();
rwi->Render();
You just have to change the focal point of your vtkCamera
vtkSmartPointer<vtkCamera> camera =
vtkSmartPointer<vtkCamera>::New();
camera->SetPosition(0, 0, 20);
camera->SetFocalPoint(0, 0, 10); // The center point is not 0, 0, 10

Qt instantly rotate animation

I know this may be a stupid question but I really can't seem to find an answer anywhere. I created a triangle like this:
QPolygonF triangle;
triangle.append(QPointF(0., -15));
triangle.append(QPointF(30., 0));
triangle.append(QPointF(0., 15));
triangle.append(QPointF(15., 0));
This triangle shall represent a car on my map, and I need to animate it. So i did the following:
QGraphicsItemAnimation *animation;
QGraphicsPolygonItem *clientCar;
QTimeLine *timer;
animation = new QGraphicsItemAnimation;
timer = new QTimeLine(10000);
timer->setFrameRange(0, 100);
clientCar = scene->addPolygon(triangle, myPen, myBrush)
animation->setItem(clientCar);
animation->setTimeLine(10000);
animation->setPosAt(0.f / 200.f, map.street1);
animation->setRotationAt(10.f / 200.f, 90.f);
animation->setPosAt(10.f / 200.f, map.street2);
animation->setRotationAt(20.f / 200.f, 180.f);
animation->setPosAt(20.f / 200.f, map.street3);
scene->addItem(clientCar);
ui->graphicsView->setScene(scene);
timer->start();
The problem is, when it reaches an intersection(road cross) it should rotate so that it will face the road it's going next. As you can see above, I tried using setRotationAt(), but what it does is slowly rotating between intersections until it reaches the next one. It should be turning in an instant, only when it's changing it's way. Any help?
From the doc:
QGraphicsItemAnimation will do a simple linear interpolation between
the nearest adjacent scheduled changes to calculate the matrix. For
instance, if you set the position of an item at values 0.0 and 1.0,
the animation will show the item moving in a straight line between
these positions. The same is true for scaling and rotation.
The linear interpolation part will do the trick.
So why don't you try this:
//animation->setPosAt(0.f / 200.f, map.street1);
//animation->setRotationAt(10.f / 200.f, 90.f);
//animation->setPosAt(10.f / 200.f, map.street2);
//animation->setRotationAt(20.f / 200.f, 180.f);
//animation->setPosAt(20.f / 200.f, map.street3);
static float const eps = 1.f / 200.f;
QVector<float> steps = {0.f, 10.f / 200.f, 20.f / 200.f};
QVector<QPointF> points = {map.street1, map.street2, map.street3};
QVector<float> angles = {0, 90.f, 180.f};
// initial conditions
animation->setPosAt(steps[0], points[0]);
animation->setRotationAt(steps[0], angles[0]);
// for each intersection
for(size_t inters = 1; inters < points.size(); ++inters)
{
animation->setRotationAt(steps[inters] - eps, angles[inters - 1]);
animation->setPosAt(steps[inters], points[inters]);
animation->setRotationAt(steps[inters] + eps, angles[inters]);
}

How to rotate the physics or dynamic body along an arc path in cocos2d(box2D)

As I am newbie to cocoa2d I am struggling alot to rotate the physics or dynamic body along an arc path.
The way I tried is as follows:
#define COS_ANIMATOR(position, timeCount, speed, waveMagnitude) ((cosf(timeCount * speed) * waveMagnitude) + position)
#define SIN_ANIMATOR(position, timeCount, speed, waveMagnitude) ((sinf(timeCount * speed) * waveMagnitude) + position)
CCSpriteBatchNode *pipe_parent = [CCSpriteBatchNode batchNodeWithFile:#"pipe.png" capacity:100];
CCTexture2D *pipeSpriteTexture_ = [pipe_parent texture];
PhysicsSprite *pipeSprite = [PhysicsSprite spriteWithTexture:pipeSpriteTexture_ rect:CGRectMake(0 ,0 ,55,122)];
//pipe = [CCSprite spriteWithFile:#"pipe.png"
// rect:CGRectMake(0, 0, 55, 122)];
[self addChild:pipeSprite];
// pipe.position = ccp(s.width/2 , 420.0);
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody; //this will be a dynamic body
myBodyDef.position.Set(((s.width/2) - 90)/PTM_RATIO, 420.0/PTM_RATIO); //set the starting position
myBodyDef.angle = 0; //set the starting angle
b2Body* staticBody = world->CreateBody(&myBodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
boxFixtureDef.userData = pipeSprite;
boxFixtureDef.filter.groupIndex = -1;
staticBody->CreateFixture(&boxFixtureDef);
[pipeSprite setPhysicsBody:staticBody];
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
const CGPoint newSpritePosition = ccp(COS_ANIMATOR(150, mTimeCounter, 0.05,50), SIN_ANIMATOR(400, mTimeCounter, -0.05, 50));
pipeSprite.position = newSpritePosition;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
on following this approach my sprite rotating in circular motion instead of rotating in an arc path.
Please give your ideas or suggestions.
Thanks all
I'm not entirely sure what it is you are looking to accomplish when you talk about rotating in an arc path. I only see you setting a position, not a rotation, so are you just wanting to set a position, or a rotation, or both? Your position code looks like you are trying to achieve a circular (or elliptical) path because you are using the sine and cosine in the x,y position.
If you're looking to move a sprite along a sine curve, I did that today and it took a bit of trial and error. I had some variables for the amplitude and period, and from there I traced out a nice sine curve movement in the sprite's update: method.
CGPoint initialPosition; // set this to the sprite's initial position
float amplitude; // in points
float period; // in points
float y, x = initialPosition.x;
-(void) update:(ccTime)dt
{
x += dt * 100; // speed of movement across the screen. Picked by trial and error.
y = initalPosition.y + amplitude * sinf((x - initialPosition.x)/period);
sprite.position = ccp(x,y);
sprite.rotation = cosf((x - initialPosition.x)/period); // optional if you want to rotate along the path as well
}
Don't know if this is anything you are looking for but it might give you some ideas.