vtk image sampling behavior changes?

We are trying to update our VTK version used in MOOSE from 9.2.6 to 9.3.0. (We are often limited in our version choices by interactions of conda feedstocks involving mpi, clang, etc.). That attempted update is occurring at Add OpenMPI variants to MOOSE development packages, add Python 3.11 support by milljm · Pull Request #26848 · idaholab/moose · GitHub. However, we are running into test regressions for our image sampling capabilities. Unfortunately, the developer who wrote this class which wraps VTK is no longer with us. From our wrapper header these are some of the VTK data structures involved

  /// List of file names to extract data
  vtkSmartPointer<vtkStringArray> _files;

  /// Complete image data
  vtkImageData * _data;

  /// VTK-6 seems to work better in terms of "algorithm outputs" rather than vtkImageData pointers...
  vtkAlgorithmOutput * _algorithm;

  /// Complete image data
  vtkSmartPointer<vtkImageReader2> _image;

  /// Pointer to thresholding filter
  vtkSmartPointer<vtkImageThreshold> _image_threshold;

  /// Pointer to the shift and scaling filter
  vtkSmartPointer<vtkImageShiftScale> _shift_scale_filter;

  /// Pointer to the magnitude filter
  vtkSmartPointer<vtkImageMagnitude> _magnitude_filter;

Have there been any notable changes to the behavior of these classes between 9.2.6 and 9.3.0? Any suggestions how we should proceed?

For the devoted reader, the MOOSE image sampler header and implementation are here and here respectively.

Could you share what the regressions looks like ?


The first screenshot is the old result from our image sampler. The second screenshot is the new result. So it seems like the results are qualitatively the same but the minimum value is 0 for the former but 5.7e4 for the latter. The maximum is the same for both. Below I’ve attached the original image we’re sampling.

test_00

These two renderings are the same, but one is more zoomed in than the other and the legend is not at the same location.

Also this looks like this was generated with ParaView, not VTK directly.

In any case, I do not see any image sample changes here.

The MOOSE regression test is a bit convoluted. It reads in the image using the class I linked to in the original post, stores it in a variable (u), and then writes to exodus. So yes I’ve opened the exodus file in paraview, which shows that the lower bound for the variable u (populated by the vtk image sampler) is different, 0 vs. 5.7e4

Indeed, completely missed that. Can you share that exodus file ?

Sorry for the delay. It doesn’t seem like “new users” can upload attachments here. I don’t even know how I got those screenshots up before

I guess some extensions must be white-listed. My hack attempt to give the exodus files png extensions didn’t work

Ok I put them up on github at misc/older-vtk-image-mesh-2d-out.e at main · lindsayad/misc · GitHub and misc/vtk-9.3-image-mesh-2d-out.e at main · lindsayad/misc · GitHub

I confirm that there two files are different, but I’m confused how does that relate to VTK.

Have these exodus files been generated with VTK ? Could you share that code ?

The source code is at moose/framework/src/utils/ImageSampler.C at next · idaholab/moose · GitHub . A bisect showed that the behavior change occurred with

commit bfe7cf9973b2533e9b1e09f9df72635e69c31013
Merge: 9bbb9c6002 f931c902b7
Author: David Gobbi <david.gobbi@gmail.com>
Date:   Thu Jul 7 19:55:46 2022 +0000

    Merge topic 'image-magnitude-double'
    
    f931c902b7 Remove vtkImageEllipsoid cast to float
    7010877421 Use double precision in vtkImageMagnitude/DotProduct
    
    Acked-by: Kitware Robot <kwrobot@kitware.com>
    Acked-by: Sean McBride <sean@rogue-research.com>
    Merge-request: !9361

 Imaging/General/vtkImageRange3D.cxx    | 9 ++++-----
 Imaging/General/vtkImageVariance3D.cxx | 9 ++++-----
 Imaging/Math/vtkImageDotProduct.cxx    | 4 ++--
 Imaging/Math/vtkImageMagnitude.cxx     | 4 ++--
 4 files changed, 12 insertions(+), 14 deletions(-)

So, if I understand well, this change (by @dgobbi ) changed the behavior of vtkImageMagnitude that you are using in MOOSE code.

Looking at the changes themselves: https://gitlab.kitware.com/vtk/vtk/-/merge_requests/9361/
A change of behavior is not expected apart in edge cases where this MR is fixing a bug.

So you may be unto something and there may be a bug in these changes, I fail to see it for now though.

Yea so going through all of our tests, I do think the changes introduced by that MR were good ones. So I consider this solved!

The diff in question seems to be this one, which is computing

magnitude = sqrt(R*R + G*G + B*B)

for the input RGB image

       sum = 0.0;
       for (idxC = 0; idxC < maxC; idxC++)
       {
-        sum += static_cast<float>(*inSI * *inSI);
+        sum += static_cast<double>(*inSI) * static_cast<double>(*inSI);
         ++inSI;
       }
       *outSI = static_cast<T>(sqrt(sum));

In this case the input RGB is 16 bits per component. Specifically, there are two colors here and the interpolated values between those two colors.

color1 = [24414, 40606, 41120]
color2 = [56557,  6160,  6160]

Using ‘float’ for the sum of squares here is a little bit lossy, whereas ‘double’ has enough bits to do the math exactly for 16-bit input. However, the difference is tiny, after the square root the difference is on the order of 0.001. In the final interpolated image you should only see a very small number of pixels change by either +1 or -1, never more than that.