diff --git a/Documentation/release/dev/add-oriented-image-support-probe-filter.md b/Documentation/release/dev/add-oriented-image-support-probe-filter.md
new file mode 100644
index 0000000000000000000000000000000000000000..740ee57053f1f616c49b5f1d0ff10768d9fbe92f
--- /dev/null
+++ b/Documentation/release/dev/add-oriented-image-support-probe-filter.md
@@ -0,0 +1,5 @@
+## Add support for oriented images in vtkProbeFilter
+
+vtkProbeFilter has been improved to support oriented images.
+The implementation now rely on the native support of orientation
+in the API of vtkImageData.
diff --git a/Filters/Core/Testing/Cxx/TestProbeFilter.cxx b/Filters/Core/Testing/Cxx/TestProbeFilter.cxx
index 0cfbc0560a6e1e39942d7b64d111745ec18d9d04..d1b72049755a28add9bb6d347e6aab4aedf36b3b 100644
--- a/Filters/Core/Testing/Cxx/TestProbeFilter.cxx
+++ b/Filters/Core/Testing/Cxx/TestProbeFilter.cxx
@@ -4,18 +4,20 @@
 #include "vtkArrayCalculator.h"
 #include "vtkDataArray.h"
 #include "vtkDataSet.h"
+#include "vtkImageData.h"
 #include "vtkLineSource.h"
 #include "vtkNew.h"
 #include "vtkPointData.h"
 #include "vtkProbeFilter.h"
+#include "vtkRTAnalyticSource.h"
 
 // Gets the number of points the probe filter counted as valid.
 // The parameter should be the output of the probe filter
-int GetNumberOfValidPoints(vtkDataSet* pd)
+vtkIdType GetNumberOfValidPoints(vtkDataSet* pd)
 {
   vtkDataArray* data = pd->GetPointData()->GetScalars("vtkValidPointMask");
-  int numValid = 0;
-  for (int i = 0; i < data->GetNumberOfTuples(); ++i)
+  vtkIdType numValid = 0;
+  for (vtkIdType i = 0; i < data->GetNumberOfTuples(); ++i)
   {
     if (data->GetVariantValue(i).ToDouble() == 1)
     {
@@ -25,8 +27,27 @@ int GetNumberOfValidPoints(vtkDataSet* pd)
   return numValid;
 }
 
+bool TestProbeFilterWithProvidedData(
+  vtkDataSet* input, vtkDataSet* source, vtkIdType expectedNValidPoints)
+{
+  vtkNew<vtkProbeFilter> probe;
+  probe->SetInputData(input);
+  probe->SetSourceData(source);
+  probe->Update();
+
+  vtkIdType nValidPoints = GetNumberOfValidPoints(probe->GetOutput());
+  if (nValidPoints != expectedNValidPoints)
+  {
+    std::cerr << "Unexpected number of valid points, got " << nValidPoints << " instead of "
+              << expectedNValidPoints << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
 // Tests the CompteThreshold and Threshold parameters on the vtkProbeFilter
-int TestProbeFilterThreshold()
+bool TestProbeFilterThreshold()
 {
   vtkNew<vtkLineSource> line1;
   line1->SetPoint1(-1, 0, 0);
@@ -51,7 +72,7 @@ int TestProbeFilterThreshold()
   int validDefault = GetNumberOfValidPoints(probe->GetOutput());
   if (validDefault != 2)
   {
-    return 1;
+    return false;
   }
   // turn off computing tolerance and set it to 11 times what is was.
   // 11 is magic number to get all the points within line1 selected.
@@ -63,19 +84,56 @@ int TestProbeFilterThreshold()
 
   if (validNext != 11)
   {
-    return 1;
+    return false;
   }
   // threshold is still set high, but we tell it to ignore it
   probe->SetComputeTolerance(true);
   probe->Update();
 
   int validIgnore = GetNumberOfValidPoints(probe->GetOutput());
-  return (validIgnore == 2) ? 0 : 1;
+  return (validIgnore == 2) ? true : false;
+}
+
+// Test probing one image into another
+bool TestProbeFilterWithImages()
+{
+  // Create Pipeline
+  vtkNew<vtkRTAnalyticSource> wavelet;
+  wavelet->SetWholeExtent(0, 16, 0, 16, 0, 16);
+  wavelet->SetCenter(8, 8, 8);
+  wavelet->Update();
+
+  vtkNew<vtkImageData> img;
+  img->SetExtent(1, 15, 1, 15, 1, 15);
+  img->SetOrigin(1, 1, 1);
+
+  return TestProbeFilterWithProvidedData(img, wavelet->GetOutput(), 3375);
+}
+
+// Test probing one image into an oriented one
+bool TestProbeFilterWithOrientedImages()
+{
+  // Create Pipeline
+  vtkNew<vtkRTAnalyticSource> wavelet;
+  wavelet->SetWholeExtent(0, 16, 0, 16, 0, 16);
+  wavelet->SetCenter(8, 8, 8);
+  wavelet->Update();
+
+  vtkNew<vtkImageData> img;
+  img->SetExtent(1, 15, 1, 15, 1, 15);
+  img->SetOrigin(1, 1, 1);
+  img->SetDirectionMatrix(0.7, -0.7, 0, 0.7, 0.7, 0, 0, 0, 1);
+
+  return TestProbeFilterWithProvidedData(img, wavelet->GetOutput(), 1575);
 }
 
 // Currently only tests the ComputeThreshold and Threshold.  Other tests
 // should be added
 int TestProbeFilter(int, char*[])
 {
-  return TestProbeFilterThreshold();
+  bool status = true;
+  status &= TestProbeFilterThreshold();
+  status &= TestProbeFilterWithImages();
+  status &= TestProbeFilterWithOrientedImages();
+  return status ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/Filters/Core/Testing/Cxx/TestResampleToImage.cxx b/Filters/Core/Testing/Cxx/TestResampleToImage.cxx
index 106ef390f22e901daa3285001adaf0dbe44877b4..1016b9e27a115a0042b7ee5b9f9d326732f6cbba 100644
--- a/Filters/Core/Testing/Cxx/TestResampleToImage.cxx
+++ b/Filters/Core/Testing/Cxx/TestResampleToImage.cxx
@@ -87,6 +87,7 @@ int TestResampleToImage(int, char*[])
   }
 
   // Test for ParaView issue #19856
+  // Please note that #19856 is not fully fixed yet, but the test below still has value
 
   vtkNew<vtkCellTypeSource> cellTypeSource;
   cellTypeSource->SetCellOrder(1);
@@ -116,9 +117,9 @@ int TestResampleToImage(int, char*[])
   {
     zeros += !val;
   }
-  if (zeros != 744732)
+  if (zeros != 744725)
   {
-    std::cout << "Caught " << zeros << " invalid points, it should have been 744732" << std::endl;
+    std::cout << "Caught " << zeros << " invalid points, it should have been 744725" << std::endl;
     status = 1;
   }
 
diff --git a/Filters/Core/Testing/Cxx/TestResampleToImage2D.cxx b/Filters/Core/Testing/Cxx/TestResampleToImage2D.cxx
index 6209ff48977e00d4fe5335b39e2b63277e046b07..c18b0c2beb50faa1748d3f7996714cc6aade46de 100644
--- a/Filters/Core/Testing/Cxx/TestResampleToImage2D.cxx
+++ b/Filters/Core/Testing/Cxx/TestResampleToImage2D.cxx
@@ -31,6 +31,7 @@ int TestResampleToImage2D(int argc, char* argv[])
   if (range[1] - range[0] < 0.01)
   {
     cerr << "Error resampling along X" << endl;
+    return EXIT_FAILURE;
   }
 
   // test on Y
@@ -41,6 +42,7 @@ int TestResampleToImage2D(int argc, char* argv[])
   if (range[1] - range[0] < 0.01)
   {
     cerr << "Error resampling along Y" << endl;
+    return EXIT_FAILURE;
   }
 
   // test on Z
@@ -51,6 +53,7 @@ int TestResampleToImage2D(int argc, char* argv[])
   if (range[1] - range[0] < 0.01)
   {
     cerr << "Error resampling along Z" << endl;
+    return EXIT_FAILURE;
   }
 
   return EXIT_SUCCESS;
diff --git a/Filters/Core/vtkProbeFilter.cxx b/Filters/Core/vtkProbeFilter.cxx
index 2ca2135ff9f8b82dc4fd3fb032e750e9efc8814c..3249c931fb6accde3c36451e3cc6ff7e29f6457a 100644
--- a/Filters/Core/vtkProbeFilter.cxx
+++ b/Filters/Core/vtkProbeFilter.cxx
@@ -755,53 +755,72 @@ void vtkProbeFilter::ProbeEmptyPoints(
 }
 
 //------------------------------------------------------------------------------
-static void GetPointIdsInRange(double rangeMin, double rangeMax, double start, double stepsize,
-  int numSteps, int& minid, int& maxid)
+void vtkProbeFilter::ProbeImagePointsInCell(vtkGenericCell* cell, vtkIdType cellId,
+  vtkDataSet* source, int srcBlockId, vtkImageData* input, vtkPointData* outPD, char* maskArray,
+  double* wtsBuff)
 {
-  if (stepsize == 0)
-  {
-    minid = maxid = 0;
-    return;
-  }
+  vtkPointData* pd = source->GetPointData();
+  // 1. get coordinates of sampling grids
 
-  minid = vtkMath::Ceil((rangeMin - start) / stepsize);
-  if (minid < 0)
+  // Recover cell bounds
+  double cellBounds[6];
+  source->GetCellBounds(cellId, cellBounds);
+  vtkBoundingBox cellBB(cellBounds);
+
+  // Recover input bounds, we already know they intersect, but reduce cellbounds
+  // to input bounds to ensure ComputeStructuredCoordinates works as expected on
+  // the edges of the input bounds
+  double inBounds[6];
+  input->GetBounds(inBounds);
+  cellBB.IntersectBox(inBounds);
+
+  // If ComputeTolerance is set, compute a tolerance proportional to the
+  // cell length. Otherwise, use the user specified absolute tolerance.
+  double tol2;
+  if (this->ComputeTolerance)
   {
-    minid = 0;
+    const vtkBoundingBox bbox(cellBounds);
+    tol2 = CELL_TOLERANCE_FACTOR_SQR * bbox.GetDiagonalLength2();
   }
-
-  maxid = vtkMath::Floor((rangeMax - start) / stepsize);
-  if (maxid > numSteps - 1)
+  else
   {
-    maxid = numSteps - 1;
+    tol2 = this->Tolerance * this->Tolerance;
   }
-}
 
-//------------------------------------------------------------------------------
-void vtkProbeFilter::ProbeImagePointsInCell(vtkGenericCell* cell, vtkIdType cellId,
-  vtkDataSet* source, int srcBlockId, const double start[3], const double spacing[3],
-  const int dim[3], vtkPointData* outPD, char* maskArray, double* wtsBuff)
-{
-  vtkPointData* pd = source->GetPointData();
-
-  // get coordinates of sampling grids
-  double cellBounds[6];
-  source->GetCellBounds(cellId, cellBounds);
+  // Iterate on each point of the bounding box
+  // to identify the covered grid
+  int* inputExtent = input->GetExtent();
+  int idxBounds[6] = { std::numeric_limits<int>::max(), std::numeric_limits<int>::min(),
+    std::numeric_limits<int>::max(), std::numeric_limits<int>::min(),
+    std::numeric_limits<int>::max(), std::numeric_limits<int>::min() };
+  double corner[3];
+  int ijk[3];
+  double pCoords[3];
+  bool found = false;
+  for (int i = 0; i < 8; i++)
+  {
+    cellBB.GetCorner(i, corner);
+    if (input->ComputeStructuredCoordinates(corner, ijk, pCoords, tol2))
+    {
+      found = true;
+      for (int j = 0; j < 3; j++)
+      {
+        idxBounds[2 * j] = std::min(ijk[j], idxBounds[2 * j]);
 
-  int idxBounds[6];
-  GetPointIdsInRange(
-    cellBounds[0], cellBounds[1], start[0], spacing[0], dim[0], idxBounds[0], idxBounds[1]);
-  GetPointIdsInRange(
-    cellBounds[2], cellBounds[3], start[1], spacing[1], dim[1], idxBounds[2], idxBounds[3]);
-  GetPointIdsInRange(
-    cellBounds[4], cellBounds[5], start[2], spacing[2], dim[2], idxBounds[4], idxBounds[5]);
+        // Force a +1 here to ensure we get even the edge of the input
+        // In some case that can be outside of the input image
+        int externalExtent = std::min(ijk[j] + 1, inputExtent[2 * j + 1]);
+        idxBounds[2 * j + 1] = std::max(externalExtent, idxBounds[2 * j + 1]);
+      }
+    }
+  }
 
-  if ((idxBounds[1] - idxBounds[0]) < 0 || (idxBounds[3] - idxBounds[2]) < 0 ||
-    (idxBounds[5] - idxBounds[4]) < 0)
+  if (!found)
   {
     return;
   }
 
+  // 2. Recover the cell to process
   source->GetCell(cellId, cell);
 
   double cpbuf[3];
@@ -814,35 +833,23 @@ void vtkProbeFilter::ProbeImagePointsInCell(vtkGenericCell* cell, vtkIdType cell
     closestPoint = nullptr;
   }
 
-  // If ComputeTolerance is set, compute a tolerance proportional to the
-  // cell length. Otherwise, use the user specified absolute tolerance.
-  double tol2;
-  if (this->ComputeTolerance)
+  // 3. Check each indices from the grid
+  for (ijk[2] = idxBounds[4]; ijk[2] <= idxBounds[5]; ijk[2]++)
   {
-    const vtkBoundingBox bbox(cellBounds);
-    tol2 = CELL_TOLERANCE_FACTOR_SQR * bbox.GetDiagonalLength2();
-  }
-  else
-  {
-    tol2 = this->Tolerance * this->Tolerance;
-  }
-  for (vtkIdType iz = idxBounds[4]; iz <= idxBounds[5]; iz++)
-  {
-    double p[3];
-    p[2] = start[2] + iz * spacing[2];
-    for (vtkIdType iy = idxBounds[2]; iy <= idxBounds[3]; iy++)
+    for (ijk[1] = idxBounds[2]; ijk[1] <= idxBounds[3]; ijk[1]++)
     {
-      p[1] = start[1] + iy * spacing[1];
-      for (vtkIdType ix = idxBounds[0]; ix <= idxBounds[1]; ix++)
+      for (ijk[0] = idxBounds[0]; ijk[0] <= idxBounds[1]; ijk[0]++)
       {
         // skip processed points
-        const vtkIdType ptId = ix + dim[0] * (iy + dim[1] * iz);
+        const vtkIdType ptId = input->ComputePointId(ijk);
         if (maskArray[ptId] == 1)
         {
           continue;
         }
-        // For each grid point within the cell bound, interpolate values
-        p[0] = start[0] + ix * spacing[0];
+
+        // record point coordinates
+        double p[3];
+        input->GetPoint(ptId, p);
 
         double pcoords[3];
         int subId;
@@ -876,14 +883,11 @@ class vtkProbeFilter::ProbeImageDataWorklet
 {
 public:
   ProbeImageDataWorklet(vtkProbeFilter* probeFilter, vtkDataSet* source, int srcBlockId,
-    const double start[3], const double spacing[3], const int dim[3], vtkPointData* outPD,
-    char* maskArray, int maxCellSize)
+    vtkImageData* input, vtkPointData* outPD, char* maskArray, int maxCellSize)
     : ProbeFilter(probeFilter)
     , Source(source)
+    , Input(input)
     , SrcBlockId(srcBlockId)
-    , Start(start)
-    , Spacing(spacing)
-    , Dim(dim)
     , OutPointData(outPD)
     , MaskArray(maskArray)
     , MaxCellSize(maxCellSize)
@@ -924,7 +928,7 @@ public:
       }
 
       this->ProbeFilter->ProbeImagePointsInCell(cell, cellId, this->Source, this->SrcBlockId,
-        this->Start, this->Spacing, this->Dim, this->OutPointData, this->MaskArray, weights);
+        this->Input, this->OutPointData, this->MaskArray, weights);
     }
   }
 
@@ -933,10 +937,8 @@ public:
 private:
   vtkProbeFilter* ProbeFilter;
   vtkDataSet* Source;
+  vtkImageData* Input;
   int SrcBlockId;
-  const double* Start;
-  const double* Spacing;
-  const int* Dim;
   vtkPointData* OutPointData;
   char* MaskArray;
   int MaxCellSize;
@@ -952,25 +954,11 @@ void vtkProbeFilter::ProbePointsImageData(
   vtkPointData* outPD = output->GetPointData();
   char* maskArray = this->MaskPoints->GetPointer(0);
 
-  //----------------------------------------
-  double spacing[3];
-  input->GetSpacing(spacing);
-  int extent[6];
-  input->GetExtent(extent);
-  int dim[3];
-  input->GetDimensions(dim);
-  double start[3];
-  input->GetOrigin(start);
-  start[0] += static_cast<double>(extent[0]) * spacing[0];
-  start[1] += static_cast<double>(extent[2]) * spacing[1];
-  start[2] += static_cast<double>(extent[4]) * spacing[2];
-
   vtkIdType numSrcCells = source->GetNumberOfCells();
-
   if (numSrcCells > 0)
   {
     ProbeImageDataWorklet worklet(
-      this, source, srcIdx, start, spacing, dim, outPD, maskArray, source->GetMaxCellSize());
+      this, source, srcIdx, input, outPD, maskArray, source->GetMaxCellSize());
     vtkSMPTools::For(0, numSrcCells, worklet);
   }
 
diff --git a/Filters/Core/vtkProbeFilter.h b/Filters/Core/vtkProbeFilter.h
index 14ea55508899ddbbc31561bc5d2005cabfa7e91b..ba11ab73ee8fcde895353d99794d4119267b7494 100644
--- a/Filters/Core/vtkProbeFilter.h
+++ b/Filters/Core/vtkProbeFilter.h
@@ -300,8 +300,7 @@ private:
   void ProbePointsImageData(
     vtkImageData* input, int srcIdx, vtkDataSet* source, vtkImageData* output);
   void ProbeImagePointsInCell(vtkGenericCell* cell, vtkIdType cellId, vtkDataSet* source,
-    int srcBlockId, const double start[3], const double spacing[3], const int dim[3],
-    vtkPointData* outPD, char* maskArray, double* wtsBuff);
+    int srcBlockId, vtkImageData* input, vtkPointData* outPD, char* maskArray, double* wtsBuff);
 
   class ProbeImageDataWorklet;