Applying georeferenced image to topo surface

(Cornelis Bockemühl) #1

After finding out how nicely the GDAL library is giving me the georeferencing not only of Geotiff files, but also other types of georeferencing (like ESRI world files), I was able to generate a filter like the “Texture Map to Plane”, but not taking coordinates as input, but the user is asked to specify a georeferenced image file. The filter uses internally the “Texture Map to Plane” to do it’s job.

With this, the user is then able to go to the “Display” section of the property panel and load the same file again as a texture.

But this is for a user not really intuitive: Why should he load the same file twice - once for defining the texture and then once again for the actual texturing?

I found some “plain VTK” example code that does the trick of applying first texture mapping to a quad, then also the texture - in one run: https://vtk.org/Wiki/VTK/Examples/Cxx/Visualization/TextureMapQuad

There they use a vtkTexture object, a vtkPolyDataMapper and finally bring everything together with a vtkActor - but there I am lost how to apply this logic inside paraview and where I would have to put such kind of code: maybe not in the “RequestData” function of my filter code!? But where else!?

Any helpful hint or example?

Of course this “one step texturing” is the “nice to have” part of my job: the automatic extraction of texture coordinates from the image georeferencing is already the big achievement - and if it is not otherwise possible, I will have to explain the customers that they need to load the image twice - no matter if they find it intuitive or not… :wink:

(Cornelis Bockemühl) #2

Digging more in the different VTK classes, trying to understand the logic of how “items” are displayed in a 3D view and texture is applied, I am getting the impression that I should possibly try the opposite way than starting with a “filter” and try to “hack in” also the functionality to apply also the actual texture - which is basically the job of the “representation”.

I might instead have to derive an own “representation” plugin that extends the texturing feature to reading and evaluating georeferencing info, generate the texture coordinates from it and do the actual texturing. Maybe this would also open the way to stopping the automatic tiling - which is not very useful in the case of projecting maps or aerial photos on a topo surface!

(Cornelis Bockemühl) #3

One step further now!!

Instead of writing a filter, I tried my luck now indeed with a “Surface with Texture” “representation” plugin. (Yes it was very helpful that this was not my first “representation plugin”!).

And it works so far that the user can now load a topo surface (“poly data” - triangulated surface), then switch to the “Surface with Texture” representation, and in the “Display” property panel choose a texture file: If that file comes with georeferencint information, such as Geotiff or ESRI world file, this will be automatically applied (thanks to the GDAL reader!) and the texture projected to the right position.

Only two problems still open:

  • for some reason the display of the image is now only black and white instead of in color: looks like I am still missing some setting somewhere

  • the texture mapping is also still “tiled” which I need to somehow get rid of: It simply makes no sense for aerial photos, maps etc. on a topo!

But now from within the “representation” logic, I have access to all the classes/objects that look relevant for this kind of action: the “texture”, the “actor”, whatever…

(Cornelis Bockemühl) #4

…and one more thing: I my new “solution” the bitmap image is now also upside down, not only black/white…

Anyway, it looks like I will have to study the roles of the “texture”, “mapper” and “actor” classes now in this context - and which one would be responsible for which of the effects: “upside down” - “coloring” - “tiling or not”.

The good thing is that they are in the “representation” all available - because they are in the parent class (or rather the parent’s parent - and accessible because “protected”: vtkGeometryRepresentation).

And the other good thing is that the cooperation of these three is very well explained in this example: https://vtk.org/Wiki/VTK/Examples/Cxx/Visualization/TextureMapQuad. Only I need to find out now which one does what!

(Cornelis Bockemühl) #5

Just reporting progress and problems - step by step.

  1. the vertical mirroring of the image was a question of applying the georeferencing info properly - now everything ok.

  2. the “tiling” I could turn of after I realized that it is called “repeating” in “VTK language”

However, now I get the thing that is called “clamping” (even with "EdgeClampOff), i.e. the edge pixels of the image are repeated “infinitely”. It looks like the “classical solution” for that problem is to apply a 1 pixel padding with a color, like white, to all edges of the image, which is supposed to be possible with the vtkImageConstantPad filter.

But this ends in a crash - and I have no idea what could be wrong with the following code:

// use the GDAL raster reader to read the raster image
vtkSmartPointer<vtkGDALRasterReader> rasterReader = vtkSmartPointer<vtkGDALRasterReader>::New();
rasterReader->SetFileName(MapFileName);
rasterReader->Update();

// get the extent of the image and extend it by 1 in x and y directions
int extent[6];
rasterReader->GetOutput()->GetExtent(extent);
--extent[0];
++extent[1];
--extent[2];
++extent[3];

// add a white 1 pixel "boundary" to the image - for filling the rest of the surface
vtkSmartPointer<vtkImageConstantPad> imgPad = vtkSmartPointer<vtkImageConstantPad>::New();
imgPad->SetInputData(rasterReader->GetOutput());
imgPad->SetOutputWholeExtent(extent);
imgPad->SetConstant(0.);
imgPad->Update();

The error message is:

ERROR: In C:\dev\pv\src\VTK\Common\DataModel\vtkImageData.cxx, line 1342
vtkImageData (000001BA1CA81560): No Scalar Field has been specified - assuming 1 component!

I can turn it round like I want, but I can see no real error in that code, also comparing with tons of examples where others seem to have used that vtkImageConstantPad filter successfully!

Still also I did not find a solution to solve the color problem.

Below you can see a screenshot of “manual” georeferenced texturing with a Geotiff, using the normal “Surface” view, and right a screenshot of my current “state of the art”. You see that I already got rid of the “tiling”, but still the colors are not there, and the “clamping” is ugly for this case.

(Cornelis Bockemühl) #6

Again one step further…

I realized that the GDAL raster reader (which is derived from vtkImageReader2) does some data transformation in the sense that it delivers always only one data item (scalar) per pixel and transforms it into double. The idea is obviously that typical Geotiff images are not really “images”, but actually elevation values, and as such this is working very well.

So I could solve my above problems by reading the same image once more, now with the vtkImageReader2, and this solves already two of my above problems:

  1. it will give me the data in the form that they are in the image file, so if it is RGB it will be “3 scalar components” etc. And the display is colored like in the left part of my screenshot in the previous message.

  2. with input from the vtkImageReader2, also the padding filter does not crash any more: it allows me to add one pixel all around the edges of the image.

Only one last cosmetic problem remaining: the vtkImageConstantPad filter allows me to set a “constant value” for the extra pixels. However, what I would like to do is: specify a color! But whatever value I set with the SetConstant function - the result is always black. Ok, better than both tiling and clamping anyway, so I am already quite happy now!

grafik

(Cornelis Bockemühl) #7

It’s finally done!

I was wrong with the statement that no matter what “constant” value I give to the vtkImageConstantPad filter would bring me a black background! My assumption actually was that because SetConstant takes a double, values should be between 0 and 1.

However, making it 255 will give me the RGB color [255,255,255] - which is what I wanted to achieve:

grafik

So I am clapping my own shoulders :wink: and proceed to the next jobs…