Skip to content

Instantly share code, notes, and snippets.

@benoitrosa
Created October 3, 2017 16:38
Show Gist options
  • Save benoitrosa/ffdb96eae376503dba5ee56f28fa0943 to your computer and use it in GitHub Desktop.
Save benoitrosa/ffdb96eae376503dba5ee56f28fa0943 to your computer and use it in GitHub Desktop.

Revisions

  1. benoitrosa created this gist Oct 3, 2017.
    128 changes: 128 additions & 0 deletions VTK_camera_intrinsics.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,128 @@
    import vtk
    import numpy as np
    from vtk.util import numpy_support
    import cv2



    class Camera_VTK():
    """
    Example class showing how to project a 3D world coordinate onto a 2D image plane using VTK
    """

    def __init__(self, w, h, P, K):
    self.w = w
    self.h = h

    self.P = P # position of 3D sphere

    self.K = K # Camera matrix

    self.f = np.array( [K[0,0], K[1,1]] ) # focal lengths
    self.c = K[:2,2] # principal point

    # projection of 3D sphere center onto the image plane
    self.p_im = np.dot(self.K,P.reshape(3,1)).flatten()
    self.p_im /= self.p_im[-1]

    self.init_vtk()


    def getImage(self):
    """
    Render a sphere using VTK into an image, and plot the projection of that sphere onto the image plane. They should coincide
    """
    # Set basic camera parameters in VTK
    cam = self.renderer.GetActiveCamera()
    near = 0.1
    far = 1000.0
    cam.SetClippingRange(near, far)

    # Position is at origin, looking in z direction with y down
    cam.SetPosition(0, 0, 0)
    cam.SetFocalPoint(0, 0, 1)
    cam.SetViewUp(0, -1, 0)

    w,h = self.w, self.h

    # Set window center for offset principal point
    wcx = -2.0*(self.c[0] - self.w / 2.0) / self.w
    wcy = 2.0*(self.c[1] - self.h / 2.0) / self.h
    cam.SetWindowCenter(wcx, wcy)

    # Set vertical view angle as a indirect way of setting the y focal distance
    angle = 180 / np.pi * 2.0 * np.arctan2(self.h / 2.0, self.f[1])
    cam.SetViewAngle(angle)

    # Set the image aspect ratio as an indirect way of setting the x focal distance
    m = np.eye(4)
    aspect = self.f[1]/self.f[0]
    m[0,0] = 1.0/aspect
    t = vtk.vtkTransform()
    t.SetMatrix(m.flatten())
    cam.SetUserTransform(t)

    # Render the scene into a numpy array for openCV processing
    self.renWin.Render()
    winToIm = vtk.vtkWindowToImageFilter()
    winToIm.SetInput(self.renWin)
    winToIm.Update()
    vtk_image = winToIm.GetOutput()
    width, height, _ = vtk_image.GetDimensions()
    vtk_array = vtk_image.GetPointData().GetScalars()
    components = vtk_array.GetNumberOfComponents()
    arr = cv2.flip(numpy_support.vtk_to_numpy(vtk_array).reshape(height, width, components), 0)
    arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGB)

    # Draw a circle at the projected place of the 3D sphere onto the image plane
    cv2.circle(arr,(int(self.p_im[0]),int(self.p_im[1])),5,(0,0,255),1)

    return arr



    def init_vtk(self):
    """
    Initialize VTK actors and rendering pipeline
    """
    self.shpereSource = vtk.vtkSphereSource()
    self.shpereSource.SetCenter(self.P[0],self.P[1],self.P[2])
    self.shpereSource.SetRadius(1.0)
    self.shperemapper = vtk.vtkPolyDataMapper()
    self.shperemapper.SetInputConnection(self.shpereSource.GetOutputPort())
    self.shpereactor = vtk.vtkActor()
    self.shpereactor.SetMapper(self.shperemapper)

    self.renderer = vtk.vtkRenderer()
    self.renWin = vtk.vtkRenderWindow()
    self.renWin.SetOffScreenRendering(1)

    self.renderer.AddActor(self.shpereactor)
    self.renderer.SetBackground(0.1, 0.2, 0.4)
    self.renderer.ResetCamera()

    self.renWin.AddRenderer(self.renderer)
    self.renWin.SetSize(self.w, self.h)
    self.renWin.Render()


    if __name__ == '__main__':

    fx = 500.0
    fy = 400.0
    cx = 395.0
    cy = 275.0
    w = 760
    h = 570

    K = np.array( [ [fx, 0., cx],
    [ 0. ,fx, cy],
    [0.,0.,1.]])

    P = np.array([ 11.14230157 , 11.23046172 , 28.56272345])

    test = Camera_VTK(w,h,P,K)
    arr = test.getImage()

    cv2.imshow("test", arr)
    cv2.waitKey(0)