[vtk-developers] parallel camera: how to get image to fill viewport?

David Gobbi dgobbi at atamai.com
Tue Nov 15 16:11:38 EST 2005


Hi Steve,

I suspect that the answer you seek lies not in the minds of the 
developers, nor in the documentation, but in the source.  If most of the 
other developers are like me, after a few years they forget some details 
about the code they have written.

So no guarantees here, but I've gone through exactly the set of steps 
that you are going through now, and here is what I remember:

1) In vtkImageData, world coordinates give the positions of the centers 
of the pixels.  This is something I'm 100% certain about.

2) In vtkImageActor, and in vtkImageViewer2, the centers of the pixels 
are displayed at the correct world-coordinate locations.

3) The corners of the Viewport correspond to positions at the corners of 
the screen pixels (note: screen pixels, not image data pixels).  Display 
coordinates correspond to positions at the center of screen pixels.  
That is why Viewport to Display conversion involves an offset of half a 
screen pixel.

What you want to do, if I understand, is put the edges of your image 
data at the edges of the Viewport.  You don't want the "Origin" of your 
image data to be at the edge of the viewport, since that would put the 
center of a pixel at the edge of the viewport.  Instead, you want the 
edge of your pixels to be at the edge of the viewport.

The code that I use to fit an image to the view is as follows, where 
"origin", "extent" and "spacing" are direct from the ImageData:

        xc = origin[0] + 0.5*(extent[0] + extent[1])*spacing[0]
        yc = origin[1] + 0.5*(extent[2] + extent[3])*spacing[1]
        xd = (extent[1] - extent[0] + 1)*spacing[0]
        yd = (extent[3] - extent[2] + 1)*spacing[1]
        d = camera.GetDistance()
        camera.SetParallelScale(0.5*yd)
        camera.SetFocalPoint(xc,yc,0.0)
        camera.SetPosition(xc,yc,+d)

This is equivalent to using "height/2.0", where "height" is the number 
of rows in the image multiplied by the spacing. To me, "(height-1)/2.0" 
doesn't seem to make sense, and if it works, I'm curious about why it works.

In vtkViewport::NormalizedViewportToViewport() I see this code:

    u = u * (size[0] - 1.0);
    v = v * (size[1] - 1.0);   

To me, the above two lines of Viewport code don't make sense.  The width 
of the viewport should correspond to the number of pixels across the 
viewport, since we're measuring between pixel corners, not between 
pixels centers.  I'm having a very hard time convincing myself that the 
"-1.0" belongs there.

Looking through CVS, the Viewport code for coordinate conversion was 
changed over and over again in 1999 and 2000, and not with a lot of 
confidence that the code was ever "correct".   A lot of people have been 
using the code since then, but my curiosity level has risen high enough 
that I think I'll spend a little bit more time looking at the code to 
make sure that I can't prove that it's wrong.

 - David

Steve M. Robbins wrote:

>This has elicited no response on vtkusers.  
>May I bend the ear of the vtk gods?
>
>Is my request feasible or am I on the wrong track?
>
>
>----- Forwarded message from "Steve M. Robbins" <steven.robbins at videotron.ca> -----
>
>Date: Sat, 12 Nov 2005 03:20:50 -0500
>From: "Steve M. Robbins" <steven.robbins at videotron.ca>
>Subject: [vtkusers] parallel camera: how to get image to fill viewport?
>To: VTK List <vtkusers at vtk.org>
>
>Howdy,
>
>I'm using vtkImageViewer2 to render an image.  I'd like to set the
>camera scale so that the image fills the window width or height.  
>I have 1 viewport that fills the entire window.
>
>I've set the camera to parallel projection, set the focal point to the
>centre of the image, set the position to just above the centre, and
>set view up to the Y axis.  After some time grepping through the
>sources, I've found that setting the camera parallel scale to (
>windowHeight - 1 ) / 2 works well.  See attached code for details.
>
>So I figure that if the image dimension and window dimension match,
>the transformation should be the identity.  I've stumbled across the
>following comment in vtkViewport.cxx:
>
>    // the 0.5 offset is here because the viewport uses pixel centers
>    // while the display uses pixel edges.
> 
>So I started computing the various transforms and dumping them (see
>attached code).  It turns out that my code will generate an identity
>mapping between world and viewport, but there's a half-pixel shift in
>world-to-display.  So I am presuming that the world coordinate system
>specifies pixel centres, too.  True?
>
>At any rate, I can get an identity world->viewport mapping when the
>image and viewport sizes agree, but only when they are square.
>As the attached code and output shows, when the width != height,
>I no longer get the identity.  
>
>How should I set up the camera so that the image fills the viewport?
>
>Thanks,
>-Steve
>
>P.S. Attached code was built and run against CVS HEAD, as of
>late Friday evening.  Also built and run against 4.2 with 
>similar results.
>
>
>import vtk.vtkCamera;
>import vtk.vtkCoordinate;
>import vtk.vtkRenderWindow;
>import vtk.vtkRenderer;
>import vtk.vtkVersion;
>
>public class TestParallelCamera
>{
>    static
>    {
>        System.loadLibrary( "vtkCommonJava" );
>        System.loadLibrary( "vtkFilteringJava" );
>        System.loadLibrary( "vtkIOJava" );
>        System.loadLibrary( "vtkImagingJava" );
>        System.loadLibrary( "vtkGraphicsJava" );
>        System.loadLibrary( "vtkRenderingJava" );
>    }
>
>    private final vtkRenderWindow renderWindow;
>    private final vtkRenderer renderer;
>    private final vtkCamera camera;
>
>    interface Converter 
>    {
>        public double[] convert( double x, double y );
>    }
>    
>    public TestParallelCamera()
>    {
>        renderer = new vtkRenderer();
>        //renderer.DebugOn();
>
>        renderWindow = new vtkRenderWindow();
>        renderWindow.AddRenderer( renderer );
>        
>        camera = renderer.GetActiveCamera();
>        camera.ParallelProjectionOn();
>        //camera.DebugOn();
>    }
>
>    
>    void setupCamera( int width, int height )
>    {
>        renderWindow.SetSize( width, height );
>        
>        double cameraDistance = 10;
>        double sliceHalfThickness = 1;
>        
>        double xFocal = ( width - 1 ) / 2.0;
>        double yFocal = ( height - 1 ) / 2.0;
>        
>        camera.SetFocalPoint( xFocal, yFocal, 0.0 );
>        camera.SetPosition( xFocal, yFocal, cameraDistance );
>        camera.SetViewUp( 0, 1, 0 );
>        camera.SetClippingRange( cameraDistance - sliceHalfThickness, cameraDistance + sliceHalfThickness );
>        
>        camera.SetParallelScale( ( height - 1 ) / 2.0 );
>
>        //System.out.println( renderer.Print() );
>        //System.out.println( camera.Print() );
>    }
>
>    private void dumpTransformMatrix( String title, Converter converter )
>    {
>        double[] originDisplay = converter.convert( 0, 0 );
>        double[] xDisplay = converter.convert( 1, 0 );
>        double[] yDisplay = converter.convert( 0, 1 );
>        
>        xDisplay[0] -= originDisplay[0];
>        xDisplay[1] -= originDisplay[1];
>
>        yDisplay[0] -= originDisplay[0];
>        yDisplay[1] -= originDisplay[1];
>
>        System.out.println( title );
>        System.out.println( xDisplay[0] + "   " + yDisplay[0] + "   " + originDisplay[0] );
>        System.out.println( xDisplay[1] + "   " + yDisplay[1] + "   " + originDisplay[1] );
>        System.out.println();
>    }
>
>    void dumpTransform()
>    {
>        System.out.println( "Renderer tiled aspect ratio: " + renderer.GetTiledAspectRatio() );
>        System.out.println( "Camera parallel scale: " + camera.GetParallelScale() );
>        System.out.println();
>
>        dumpTransformMatrix( "Normalized Viewport-to-Viewport transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToNormalizedViewport();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleViewportValue( renderer );
>                                }
>            
>                             } );
>        
>        dumpTransformMatrix( "Normalized Display-to-Display transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToNormalizedDisplay();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleDisplayValue( renderer );
>                                }
>            
>                             } );
>        
>        dumpTransformMatrix( "View-to-Viewport transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToView();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleViewportValue( renderer );
>                                }
>            
>                             } );
>        
>        dumpTransformMatrix( "View-to-Display transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToView();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleDisplayValue( renderer );
>                                }
>            
>                             } );
>        
>        dumpTransformMatrix( "World-to-Viewport transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToWorld();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleViewportValue( renderer );
>                                }
>            
>                             } );
>        
>        dumpTransformMatrix( "World-to-Display transform",
>                             new Converter()
>                             {
>                                public double[] convert( double x, double y )
>                                {
>                                    vtkCoordinate coord = new vtkCoordinate();
>                                    coord.SetCoordinateSystemToWorld();
>                                    coord.SetValue( x, y );
>                                    return coord.GetComputedDoubleDisplayValue( renderer );
>                                }
>            
>                             } );
>        
>    }
>    
>    public static void main( String[] args )
>    {
>        vtkVersion version = new vtkVersion();
>        System.out.println( "Loaded VTK version " + version.GetVTKVersion() );
>        System.out.println( "  Source version: " + version.GetVTKSourceVersion() );
>
>        TestParallelCamera tester = new TestParallelCamera();
>        
>        System.out.println( "5x5" );
>        tester.setupCamera( 5, 5 );
>        tester.dumpTransform();
>
>        System.out.println();
>        System.out.println( "15x5" );
>        tester.setupCamera( 15, 5 );
>        tester.dumpTransform();
>    }
>    
>}
>
>Loaded VTK version 5.1.0
>  Source version: vtk version 5.1.0, vtk source $Revision: 1.2260 $, $Date: 2005/11/11 10:51:14 $ (GMT)
>5x5
>Renderer tiled aspect ratio: 1.0
>Camera parallel scale: 2.0
>
>Normalized Viewport-to-Viewport transform
>4.0   0.0   0.0
>0.0   4.0   0.0
>
>Normalized Display-to-Display transform
>5.0   0.0   0.0
>0.0   5.0   0.0
>
>View-to-Viewport transform
>2.0   0.0   2.0
>0.0   2.0   2.0
>
>View-to-Display transform
>2.0   0.0   2.5
>0.0   2.0   2.5
>
>World-to-Viewport transform
>1.0   0.0   0.0
>0.0   1.0   0.0
>
>World-to-Display transform
>1.0   0.0   0.5
>0.0   1.0   0.5
>
>
>15x5
>Renderer tiled aspect ratio: 3.0
>Camera parallel scale: 2.0
>
>Normalized Viewport-to-Viewport transform
>14.0   0.0   0.0
>0.0   4.0   0.0
>
>Normalized Display-to-Display transform
>15.0   0.0   0.0
>0.0   5.0   0.0
>
>View-to-Viewport transform
>7.0   0.0   7.0
>0.0   2.0   2.0
>
>View-to-Display transform
>7.0   0.0   7.5
>0.0   2.0   2.5
>
>World-to-Viewport transform
>1.1666666666666665   0.0   -1.1666666666666656
>0.0   1.0   0.0
>
>World-to-Display transform
>1.1666666666666665   0.0   -0.6666666666666656
>0.0   1.0   0.5
>
>
>_______________________________________________
>This is the private VTK discussion list. 
>Please keep messages on-topic. Check the FAQ at: http://www.vtk.org/Wiki/VTK_FAQ
>Follow this link to subscribe/unsubscribe:
>http://www.vtk.org/mailman/listinfo/vtkusers
>
>
>----- End forwarded message -----
>_______________________________________________
>vtk-developers mailing list
>vtk-developers at vtk.org
>http://www.vtk.org/mailman/listinfo/vtk-developers
>
>  
>




More information about the vtk-developers mailing list