Skip to content

Commit

Permalink
Refactor image::compare (#1863)
Browse files Browse the repository at this point in the history
  • Loading branch information
Meakk authored Jan 3, 2025
1 parent 89df7ec commit 7ae6a1a
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 83 deletions.
4 changes: 2 additions & 2 deletions application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1034,9 +1034,9 @@ int F3DStarter::Start(int argc, char** argv)
f3d::image img = window.renderToImage(this->Internals->AppOptions.NoBackground);
f3d::image ref(reference);
f3d::image diff;
double error;
double error = img.compare(ref);
const double& threshold = this->Internals->AppOptions.RefThreshold;
if (!img.compare(ref, threshold, error))
if (error > threshold)
{
if (output.empty())
{
Expand Down
3 changes: 1 addition & 2 deletions examples/libf3d/cpp/render-image/check.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ int main(int argc, char** argv)
f3d::image img1(argv[2]);

// Compare them
double error;
return img0.compare(img1, 0.05, error) ? EXIT_SUCCESS : EXIT_FAILURE;
return img0.compare(img1) <= 0.05 ? EXIT_SUCCESS : EXIT_FAILURE;
}
4 changes: 1 addition & 3 deletions examples/libf3d/python/img-cmp/img-cmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
diff = f3d.Image()
error = 0.0

result = img_0.compare(img_1, 0.05, diff, error)

if result:
if img_0.compare(img_1) <= 0.05:
print("Images are identical")
else:
print("Images are different")
Expand Down
11 changes: 4 additions & 7 deletions library/public/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,23 +135,20 @@ class F3D_EXPORT image
///@}

/**
* Compare current image to a reference using the provided threshold.
* If the comparison fails, ie. error is higher than the threshold,
* this outputs the resulting diff and error and return false,
* return true otherwise.
* Compare current image to a reference.
* The error is minimum between Minkownski and Wasserstein distance
* on a SSIM computation, as specified in VTK.
* Please note, due to possible arithmetic imprecision in the SSIM computation
* using a threshold of zero may return false with identical images.
* a non-zero value can be returned with identical images.
* Depending on the VTK version, another comparison algorithm may be used.
* Threshold should be in range [0, 1[, this returns false otherwise.
* Error value meaning is described below:
* 1e-14: Pixel perfect comparison.
* 0.04: Visually indistinguishable.
* 0.1: Small visible difference.
* 0.5: Comparable images.
* 1.0: Different type, size or number of components
*/
bool compare(const image& reference, double threshold, double& error) const;
double compare(const image& reference) const;

/**
* Save an image to the provided file path, used as is, in the specified format.
Expand Down
45 changes: 11 additions & 34 deletions library/src/image.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -344,39 +344,28 @@ void* image::getContent() const
}

//----------------------------------------------------------------------------
bool image::compare(const image& reference, double threshold, double& error) const
double image::compare(const image& reference) const
{
// Sanity check for threshold
if (threshold < 0 || threshold >= 1)
{
error = 1;
return false;
}

ChannelType type = this->getChannelType();
if (type != reference.getChannelType())
{
error = 1;
return false;
return 1.0;
}

unsigned int count = this->getChannelCount();
if (count != reference.getChannelCount())
{
error = 1;
return false;
return 1.0;
}

if (this->getWidth() != reference.getWidth() || this->getHeight() != reference.getHeight())
{
error = 1;
return false;
return 1.0;
}

if (this->getWidth() == 0 && this->getHeight() == 0)
{
error = 0;
return true;
return 0.0;
}

#if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 3, 20240729)
Expand Down Expand Up @@ -406,39 +395,27 @@ bool image::compare(const image& reference, double threshold, double& error) con
// Thanks to the checks above, this is always true
assert(scalars != nullptr);

double unused;
double error, unused;
vtkImageSSIM::ComputeErrorMetrics(scalars, error, unused);
return error <= threshold;
return error;
#else
threshold *= 1000;

vtkNew<vtkImageDifference> imDiff;
imDiff->SetThreshold(0);
imDiff->SetInputData(this->Internals->Image);
imDiff->SetImageData(reference.Internals->Image);
imDiff->UpdateInformation();
error = imDiff->GetThresholdedError();

if (error <= threshold)
{
imDiff->Update();
error = imDiff->GetThresholdedError();
}

bool ret = error <= threshold;
error /= 1000;
return ret;
imDiff->Update();
double error = imDiff->GetThresholdedError();
return error / 1000.0;
#endif
}

//----------------------------------------------------------------------------
bool image::operator==(const image& reference) const
{
double error;
// XXX: We do not use 0 because even with identical images, rounding error, arithmetic imprecision
// or architecture issue may cause the value to not be 0. See:
// https://develop.openfoam.com/Development/openfoam/-/issues/2958
return this->compare(reference, 1e-14, error);
return this->compare(reference) <= 1e-14;
}

//----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions library/testing/TestSDKHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ static bool RenderTest(const f3d::image& img, const std::string& baselinePath,
}

f3d::image reference(baseline);
double error;

if (!img.compare(reference, threshold, error))
double error = img.compare(reference);

if (error > threshold)
{
std::cerr << "Current rendering difference with reference image " << baseline << " : " << error
<< " is higher than the threshold of " << threshold << std::endl;
Expand Down
44 changes: 14 additions & 30 deletions library/testing/TestSDKImage.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,8 @@ int TestSDKImage(int argc, char* argv[])
f3d::image baseline(testingDir + "/baselines/TestSDKImage.png");
if (generated != baseline)
{
double error;
generated.compare(baseline, 0, error);

std::cerr << "Generated image is different from the png baseline: " << error << std::endl;
std::cerr << "Generated image is different from the png baseline: "
<< generated.compare(baseline) << std::endl;
return EXIT_FAILURE;
}

Expand All @@ -151,10 +149,8 @@ int TestSDKImage(int argc, char* argv[])
f3d::image baselineTIF(testingDir + "/baselines/TestSDKImage.tif");
if (generated != baselineTIF)
{
double error;
generated.compare(baselineTIF, 0, error);
std::cerr << "Generated image is different from the tif baseline: " << error << std::endl;
std::cerr << "Generated image is different from the tif baseline: "
<< generated.compare(baselineTIF) << std::endl;
return EXIT_FAILURE;
}*/

Expand All @@ -171,10 +167,8 @@ int TestSDKImage(int argc, char* argv[])
f3d::image baseline16(testingDir + "/baselines/TestSDKImage16.png");
if (generated16 != baseline16)
{
double error;
generated16.compare(baseline16, 0, error);

std::cerr << "generated short image is different from the baseline: " << error << std::endl;
std::cerr << "generated short image is different from the baseline: "
<< generated16.compare(baseline16) << std::endl;
return EXIT_FAILURE;
}

Expand All @@ -183,10 +177,8 @@ int TestSDKImage(int argc, char* argv[])
f3d::image baseline16TIF(testingDir + "/baselines/TestSDKImage16.tif");
if (generated16 != baseline16TIF)
{
double error;
generated16.compare(baseline16TIF, 0, error);
std::cerr << "generated short image is different from the TIF baseline: " << error << std::endl;
std::cerr << "generated short image is different from the TIF baseline: "
<< generated16.compare(baseline16TIF) << std::endl;
return EXIT_FAILURE;
}*/

Expand All @@ -204,10 +196,8 @@ int TestSDKImage(int argc, char* argv[])

if (generated32 != baseline32)
{
double error;
generated32.compare(baseline32, 0, error);

std::cerr << "generated float image is different from the baseline: " << error << std::endl;
std::cerr << "generated float image is different from the baseline: "
<< generated32.compare(baseline32) << std::endl;
return EXIT_FAILURE;
}
#endif // F3D_SSIM_COMPARE
Expand Down Expand Up @@ -300,22 +290,16 @@ int TestSDKImage(int argc, char* argv[])
}

// Test image::compare dedicated code paths
double error;
test("compare images with different channel types",
!generated.compare(generated16, 0, error) && error == 1.);
test("compare images with different channel types", generated.compare(generated16) == 1.);

f3d::image generatedCount(width, height, channels + 1);
test("compare images with different channel count",
!generated.compare(generatedCount, 0, error) && error == 1.);
test("compare images with different channel count", generated.compare(generatedCount) == 1.);

f3d::image generatedSize(width + 1, height, channels);
test("compare images with different size",
!generated.compare(generatedSize, 0, error) && error == 1.);
test("compare images with different size", generated.compare(generatedSize) == 1.);

f3d::image empty(0, 0, 0);
test("compare empty images", empty.compare(empty, 0, error) && error == 0.);
test("compare with negative threshold", !empty.compare(empty, -1, error) && error == 1.);
test("compare with threshold == 1", !empty.compare(empty, 1, error) && error == 1.);
test("compare empty images", empty.compare(empty) == 0.);

return test.result();
}
2 changes: 1 addition & 1 deletion python/testing/test_image_compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ def test_compare_with_file():

error = 0.0

assert img.compare(f3d.Image(reference), 0.05, error)
assert img.compare(f3d.Image(reference)) <= 0.05
4 changes: 2 additions & 2 deletions python/testing/test_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_scene_memory():

error = 0.0

assert img.compare(f3d.Image(reference), 0.05, error)
assert img.compare(f3d.Image(reference)) < 0.05


def test_scene():
Expand Down Expand Up @@ -54,4 +54,4 @@ def test_scene():

error = 0.0

assert img.compare(f3d.Image(reference), 0.05, error)
assert img.compare(f3d.Image(reference)) < 0.05

0 comments on commit 7ae6a1a

Please sign in to comment.