positioning and scaling of Actor2D with image

I’m trying to display a static image in on of the corners of the screen. Like a company logo or some additional information (see Adding a logo-widget · Issue #474 · marcomusy/vedo (github.com)) .

Easiest seems to use a Actor2D in combination vtkImageMapper. But I can not figure out how to scale or position the actor. SetWidth, SetHeight do not seem to have any effect, SetPosition seems to use pixels rather than normalized screen coordinates.

I found https://stackoverflow.com/questions/9216211/how-to-position-a-vtkactor2d-in-the-upper-right-corner but I can not imagine that that is the best way to do this.

thanks!

we got a bit furher with setting imagemapper.RenderToRectangleOn() to enable scaling and using vtkCoordinates for the position.

However I fail to get the expected results when setting Position2 to Viewport-coordinates, relative to Position and providing the size of the image in pixels.

I would expect the following code to define the position of the upper-right corner relative to the
lower-left in viewport-pixels. However it acts like the coordinate system is still set to NormalizedViewport?

position2_coordinate = image.GetPosition2Coordinate()
position2_coordinate.SetReferenceCoordinate(image.GetPositionCoordinate())
position2_coordinate.SetCoordinateSystemToViewport() # x-y pixel values in viewport
position2_coordinate.SetValue(200,100) # fails  SetValue(0.2,0.1) does show the image, but keeps it relative to viewport

https://vtk.org/doc/nightly/html/classvtkLogoWidget.html

thanks Mathieu, that widget was actually the first thing I tried, but there I ran into the issue that I want the image to be static (ie, no user interaction).

.SelectableOff() should take care of that, but on my machine they don’t. ResizableOff() does work but then I can still move it.

So using an actor2d seemed to make more sense.

Sounds like a bug, probably simple to fix.

Callbacks can be used for relative positioning and scaling, using the StartEvent of the vtkRenderer. With an observer for StartEvent, you can do whatever math is needed to position the image correctly in display coordinates.

@mwestphal Its not a bug. I just misread the documentation.
the widget is either movable OR selectable. So SelectableOff() enables the possibility to move it. See also the example https://kitware.github.io/vtk-examples/site/Cxx/Interaction/ImageRegion/ where borderWidget->SelectableOff() is called to enable movement.

@dgobbi Thanks, but that does not solve the issue that I have. I can not figure out the math that is needed to position the actor correctly.

My idea was to

  • define the position2 (upper-right) relative to position (lower-left)
  • set its coordinate-system is to Viewport.
    In my understanding that would keep the actor size constant in pixels. But is doesn’t.

I don’t understand. Viewport coordinates are relative to the size of the window renderer, so different window size means different image size.

Display coordinates have a one-to-one mapping to screen pixels. So if you set the image size in display coordinates, then that’s the size that will be used.

The only difficulty that I can see with display coordinates is that they are measured from the lower-left, not the upper-right. But the math to do that in display coordinates isn’t difficult:

x = window_width - image_width - x_distance_from_right_edge - 1
y = window_height - image_height - y_distance_from_top_edge - 1

@dgobbi , thanks again for the help.

“Display coordinates have a one-to-one mapping to screen pixels. So if you set the image size in display coordinates, then that’s the size that will be used.”

So I need to use Display coordinates instead of Viewport.

then what am I doing wrong when I do:

// Read the image
  vtkNew<vtkJPEGReader> jPEGReader;
  jPEGReader->SetFileName(InputFilename.c_str());

  vtkNew<vtkImageActor> actor;
  actor->GetMapper()->SetInputConnection(jPEGReader->GetOutputPort());
  
  // Actor2D with image
  vtkNew<vtkActor2D> actor2D;
  vtkNew< vtkImageMapper>imageMapper;

  imageMapper->SetInputConnection(jPEGReader->GetOutputPort());
  imageMapper->SetColorWindow(255);
  imageMapper->SetColorLevel(127.5);
  imageMapper->RenderToRectangleOn();

// Actor2D with image
  vtkNew<vtkActor2D> actor2D;
  vtkNew< vtkImageMapper>imageMapper;

  imageMapper->SetInputConnection(jPEGReader->GetOutputPort());
  imageMapper->SetColorWindow(255);
  imageMapper->SetColorLevel(127.5);
  imageMapper->RenderToRectangleOn();

  actor2D->SetMapper(imageMapper);

  actor2D->GetPositionCoordinate()->SetValue(0, 0);

  vtkCoordinate* pos2{ actor2D->GetPosition2Coordinate() };
  pos2->SetCoordinateSystemToDisplay();
  pos2->SetValue(100, 100);

I’m expecting a 100x100 pixels image in the lower,left corner. But I get something that is stretched way beyond the screen. Like the 100 is interpreted as a normalized value.

The only difficulty that I can see with display coordinates is that they are measured from the lower-left, not the upper-right. But the math to do that in display coordinates isn’t difficult:

I just define a coordinate in the normalized viewport at (1,1) and then define position (lower,left) at (-width, -height) display-coordinates relative to that. That part actually works.

Nevermind, I think I’m confusing “viewport coordinates” and “normalized viewport coordinates”. So I’m just going to keep quiet for a while until I can find time to go back and study the docs.