change arg ordering, support setting number of error pixels allowed

This commit is contained in:
nadavi 2021-01-05 20:09:01 +00:00
parent 142a538d32
commit da751cf061
4 changed files with 129 additions and 52 deletions

@ -35,16 +35,31 @@ public:
VTKM_CONT ImageDifference();
VTKM_CONT vtkm::IdComponent GetRadius() const { return this->Radius; }
VTKM_CONT void SetRadius(const vtkm::IdComponent& radius) { this->Radius = radius; }
VTKM_CONT vtkm::FloatDefault GetThreshold() const { return this->Threshold; }
VTKM_CONT void SetThreshold(const vtkm::FloatDefault& threshold) { this->Threshold = threshold; }
VTKM_CONT bool GetAveragePixels() const { return this->AveragePixels; }
VTKM_CONT void SetAveragePixels(const bool& averagePixels)
VTKM_CONT vtkm::IdComponent GetAverageRadius() const { return this->AverageRadius; }
VTKM_CONT void SetAverageRadius(const vtkm::IdComponent& averageRadius)
{
this->AveragePixels = averagePixels;
this->AverageRadius = averageRadius;
}
VTKM_CONT vtkm::IdComponent GetPixelShiftRadius() const { return this->PixelShiftRadius; }
VTKM_CONT void SetPixelShiftRadius(const vtkm::IdComponent& pixelShiftRadius)
{
this->PixelShiftRadius = pixelShiftRadius;
}
VTKM_CONT vtkm::FloatDefault GetAllowedPixelErrorRatio() const
{
return this->AllowedPixelErrorRatio;
}
VTKM_CONT void SetAllowedPixelErrorRatio(const vtkm::FloatDefault& pixelErrorRatio)
{
this->AllowedPixelErrorRatio = pixelErrorRatio;
}
VTKM_CONT vtkm::FloatDefault GetPixelDiffThreshold() const { return this->PixelDiffThreshold; }
VTKM_CONT void SetPixelDiffThreshold(const vtkm::FloatDefault& threshold)
{
this->PixelDiffThreshold = threshold;
}
VTKM_CONT bool GetImageDiffWithinThreshold() const { return this->ImageDiffWithinThreshold; }
@ -91,9 +106,10 @@ public:
vtkm::filter::PolicyBase<DerivedPolicy> policy);
private:
vtkm::IdComponent Radius;
vtkm::FloatDefault Threshold;
bool AveragePixels;
vtkm::IdComponent AverageRadius;
vtkm::IdComponent PixelShiftRadius;
vtkm::FloatDefault AllowedPixelErrorRatio;
vtkm::FloatDefault PixelDiffThreshold;
bool ImageDiffWithinThreshold;
std::string SecondaryFieldName;
vtkm::cont::Field::Association SecondaryFieldAssociation;

@ -12,7 +12,6 @@
#include <vtkm/filter/ImageDifference.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/Logging.h>
@ -25,11 +24,25 @@ namespace vtkm
namespace filter
{
namespace detail
{
struct GreaterThanThreshold
{
GreaterThanThreshold(const vtkm::FloatDefault& thresholdError)
: ThresholdError(thresholdError)
{
}
VTKM_EXEC_CONT bool operator()(const vtkm::FloatDefault& x) const { return x > ThresholdError; }
vtkm::FloatDefault ThresholdError;
};
} // namespace detail
inline VTKM_CONT ImageDifference::ImageDifference()
: vtkm::filter::FilterField<ImageDifference>()
, Radius(0)
, Threshold(0.05f)
, AveragePixels(false)
, AverageRadius(0)
, PixelShiftRadius(0)
, AllowedPixelErrorRatio(0.0001f)
, PixelDiffThreshold(0.05f)
, ImageDiffWithinThreshold(true)
, SecondaryFieldName("image-2")
, SecondaryFieldAssociation(vtkm::cont::Field::Association::ANY)
@ -64,10 +77,11 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
vtkm::cont::ArrayHandle<T, StorageType> secondaryOutput;
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> thresholdOutput;
if (this->AveragePixels && this->Radius > 0)
if (this->AverageRadius > 0)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Performing Average with radius: " << this->Radius);
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->Radius);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Performing Average with radius: " << this->AverageRadius);
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->AverageRadius);
this->Invoke(averageWorklet, cellSet, primary, primaryOutput);
this->Invoke(averageWorklet, cellSet, secondary, secondaryOutput);
}
@ -79,10 +93,11 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
secondaryField.GetData().template Cast<vtkm::cont::ArrayHandle<T, StorageType>>();
}
if (this->Radius > 0)
if (this->PixelShiftRadius > 0)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Diffing image in Neighborhood");
auto diffWorklet = vtkm::worklet::ImageDifferenceNeighborhood(this->Radius, this->Threshold);
auto diffWorklet =
vtkm::worklet::ImageDifferenceNeighborhood(this->PixelShiftRadius, this->PixelDiffThreshold);
this->Invoke(diffWorklet, cellSet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
}
else
@ -92,17 +107,26 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
this->Invoke(diffWorklet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
}
// Dummy calculate the threshold. If any value is greater than the min our images
// are not similar enough.
vtkm::FloatDefault maxThreshold =
vtkm::cont::Algorithm::Reduce(thresholdOutput, vtkm::FloatDefault(0), vtkm::Maximum());
if (maxThreshold > this->Threshold)
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> errorPixels;
vtkm::cont::Algorithm::CopyIf(thresholdOutput,
thresholdOutput,
errorPixels,
detail::GreaterThanThreshold(this->PixelDiffThreshold));
if (errorPixels.GetNumberOfValues() >
thresholdOutput.GetNumberOfValues() * this->AllowedPixelErrorRatio)
{
this->ImageDiffWithinThreshold = false;
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Difference within threshold: " << this->ImageDiffWithinThreshold);
"Difference within threshold: "
<< this->ImageDiffWithinThreshold
<< ", for pixels outside threshold: " << errorPixels.GetNumberOfValues()
<< ", with total number of pixels: " << thresholdOutput.GetNumberOfValues()
<< ", and an allowable percentage of errored pixels: "
<< this->AllowedPixelErrorRatio << ", with a total summed threshold error: "
<< vtkm::cont::Algorithm::Reduce(errorPixels, static_cast<FloatDefault>(0)));
vtkm::cont::DataSet clone;
clone.CopyStructure(input);

@ -102,8 +102,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -125,9 +125,9 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(1);
filter.SetAveragePixels(true);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(1);
filter.SetAverageRadius(1);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -149,8 +149,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -166,6 +166,30 @@ void TestImageDifference()
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), false);
}
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Non Matching Images (Different R pixel)");
auto dataSet = FillDataSet(static_cast<vtkm::FloatDefault>(3));
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
filter.SetAllowedPixelErrorRatio(1.00f);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }
};
std::vector<vtkm::FloatDefault> expectedThreshold = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
CheckResult(
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), true);
}
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Non Matching Images (Different R pixel), Large Threshold");
@ -173,8 +197,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(3.0f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(3.0f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {

@ -38,9 +38,10 @@
template <typename ViewType>
inline TestEqualResult test_equal_images(const std::shared_ptr<ViewType> view,
const std::vector<std::string>& fileNames,
const vtkm::IdComponent& averageRadius = 0,
const vtkm::IdComponent& pixelShiftRadius = 0,
const vtkm::FloatDefault& allowedPixelErrorRatio = 0.0001f,
const vtkm::FloatDefault& threshold = 0.05f,
const vtkm::IdComponent& radius = 0,
const bool& average = false,
const bool& writeDiff = true,
const bool& returnOnPass = true)
{
@ -95,9 +96,10 @@ inline TestEqualResult test_equal_images(const std::shared_ptr<ViewType> view,
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("baseline-image");
filter.SetSecondaryField("generated-image");
filter.SetThreshold(threshold);
filter.SetRadius(radius);
filter.SetAveragePixels(average);
filter.SetAverageRadius(averageRadius);
filter.SetPixelShiftRadius(pixelShiftRadius);
filter.SetAllowedPixelErrorRatio(allowedPixelErrorRatio);
filter.SetPixelDiffThreshold(threshold);
auto resultDataSet = filter.Execute(imageDataSet);
if (!filter.GetImageDiffWithinThreshold())
@ -133,13 +135,15 @@ inline TestEqualResult test_equal_images(const std::shared_ptr<ViewType> view,
template <typename ViewType>
inline TestEqualResult test_equal_images(const std::shared_ptr<ViewType> view,
const std::string& fileName,
const vtkm::IdComponent& averageRadius = 0,
const vtkm::IdComponent& pixelShiftRadius = 0,
const vtkm::FloatDefault& allowedPixelErrorRatio = 0.0001f,
const vtkm::FloatDefault& threshold = 0.05f,
const vtkm::IdComponent& radius = 0,
const bool& average = false,
const bool& writeDiff = true)
{
std::vector<std::string> fileNames{ fileName };
return test_equal_images(view, fileNames, threshold, radius, average, writeDiff);
return test_equal_images(
view, fileNames, averageRadius, pixelShiftRadius, allowedPixelErrorRatio, threshold, writeDiff);
}
/// \brief Tests multiple images in the format `fileName#.png`
@ -156,13 +160,15 @@ inline TestEqualResult test_equal_images(const std::shared_ptr<ViewType> view,
/// test_equal_images will then be called on the vector of valid fileNames
///
template <typename ViewType>
inline TestEqualResult test_equal_images_matching_name(const std::shared_ptr<ViewType> view,
const std::string& fileName,
const vtkm::FloatDefault& threshold = 0.05f,
const vtkm::IdComponent& radius = 0,
const bool& average = false,
const bool& writeDiff = true,
const bool& returnOnPass = true)
inline TestEqualResult test_equal_images_matching_name(
const std::shared_ptr<ViewType> view,
const std::string& fileName,
const vtkm::IdComponent& averageRadius = 0,
const vtkm::IdComponent& pixelShiftRadius = 0,
const vtkm::FloatDefault& allowedPixelErrorRatio = 0.0001f,
const vtkm::FloatDefault& threshold = 0.05f,
const bool& writeDiff = true,
const bool& returnOnPass = true)
{
std::vector<std::string> fileNames;
auto found = fileName.rfind(".");
@ -183,7 +189,14 @@ inline TestEqualResult test_equal_images_matching_name(const std::shared_ptr<Vie
}
fileNames.emplace_back(fileNameStream.str());
}
return test_equal_images(view, fileNames, threshold, radius, average, writeDiff, returnOnPass);
return test_equal_images(view,
fileNames,
averageRadius,
pixelShiftRadius,
allowedPixelErrorRatio,
threshold,
writeDiff,
returnOnPass);
}