Skip to content

Commit c17267f

Browse files
Image tools: reworked GetImageDifference function
1 parent 7039a2a commit c17267f

File tree

3 files changed

+110
-51
lines changed

3 files changed

+110
-51
lines changed

Common/interface/ImageTools.h

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,43 @@ struct ImageDiffInfo
5656
};
5757
typedef struct ImageDiffInfo ImageDiffInfo;
5858

59+
60+
/// Attributes for GetImageDifference function
61+
struct GetImageDifferenceAttribs
62+
{
63+
/// Image width
64+
Uint32 Width DEFAULT_INITIALIZER(0);
65+
66+
/// Image height
67+
Uint32 Height DEFAULT_INITIALIZER(0);
68+
69+
/// A pointer to the first image data
70+
const void* pImage1 DEFAULT_INITIALIZER(nullptr);
71+
72+
/// Number of channels in the first image
73+
Uint32 NumChannels1 DEFAULT_INITIALIZER(0);
74+
75+
/// Row stride of the first image data, in bytes
76+
Uint32 Stride1 DEFAULT_INITIALIZER(0);
77+
78+
/// A pointer to the second image data
79+
const void* pImage2 DEFAULT_INITIALIZER(nullptr);
80+
81+
/// Number of channels in the second image
82+
Uint32 NumChannels2 DEFAULT_INITIALIZER(0);
83+
84+
/// Row stride of the second image data, in bytes
85+
Uint32 Stride2 DEFAULT_INITIALIZER(0);
86+
87+
/// Difference threshold
88+
Uint32 Threshold DEFAULT_INITIALIZER(0);
89+
};
90+
typedef struct GetImageDifferenceAttribs GetImageDifferenceAttribs;
91+
5992
/// Compute the difference between two images
6093
///
61-
/// \param [in] Width Image width
62-
/// \param [in] Height Image height
63-
/// \param [in] NumChannels Number of channels in the image
64-
/// \param [in] pImage1 Pointer to the first image data
65-
/// \param [in] Stride1 Row stride of the first image data, in bytes
66-
/// \param [in] pImage2 Pointer to the second image data
67-
/// \param [in] Stride2 Row stride of the second image data, in bytes
68-
/// \param [in] Threshold Difference threshold
94+
/// \param [in] Attribs Image difference attributes, see Diligent::GetImageDifferenceAttribs.
95+
///
6996
/// \return The image difference information, see Diligent::ImageDiffInfo.
7097
///
7198
/// \remarks The difference between two pixels is calculated as the maximum of the
@@ -74,16 +101,7 @@ typedef struct ImageDiffInfo ImageDiffInfo;
74101
/// The root mean square difference is calculated as the square root of
75102
/// the average of the squares of all differences, not counting pixels that
76103
/// are equal.
77-
void DILIGENT_GLOBAL_FUNCTION(GetImageDifference)(
78-
Uint32 Width,
79-
Uint32 Height,
80-
Uint32 NumChannels,
81-
const void* pImage1,
82-
Uint32 Stride1,
83-
const void* pImage2,
84-
Uint32 Stride2,
85-
Uint32 Threshold,
86-
ImageDiffInfo REF ImageDiff);
104+
void DILIGENT_GLOBAL_FUNCTION(GetImageDifference)(const GetImageDifferenceAttribs REF Attribs, ImageDiffInfo REF ImageDiff);
87105

88106

89107
// clang-format off

Common/src/ImageTools.cpp

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,49 +34,45 @@
3434
namespace Diligent
3535
{
3636

37-
void GetImageDifference(Uint32 Width,
38-
Uint32 Height,
39-
Uint32 NumChannels,
40-
const void* pImage1,
41-
Uint32 Stride1,
42-
const void* pImage2,
43-
Uint32 Stride2,
44-
Uint32 Threshold,
45-
ImageDiffInfo& Diff)
37+
void GetImageDifference(const GetImageDifferenceAttribs& Attribs,
38+
ImageDiffInfo& Diff)
4639
{
4740
Diff = {};
4841

49-
if (pImage1 == nullptr || pImage2 == nullptr)
42+
if (Attribs.pImage1 == nullptr || Attribs.pImage2 == nullptr)
5043
{
5144
UNEXPECTED("Image pointers cannot be null");
5245
return;
5346
}
5447

55-
if (Stride1 < Width * NumChannels)
48+
VERIFY(Attribs.NumChannels1 != 0, "NumChannels1 cannot be zero");
49+
if (Attribs.Stride1 < Attribs.Width * Attribs.NumChannels1)
5650
{
57-
UNEXPECTED("Stride1 is too small. It must be at least ", Width * NumChannels, " bytes long.");
51+
UNEXPECTED("Stride1 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels1, " bytes long.");
5852
return;
5953
}
6054

61-
if (Stride2 < Width * NumChannels)
55+
VERIFY(Attribs.NumChannels2 != 0, "NumChannels2 cannot be zero");
56+
if (Attribs.Stride2 < Attribs.Width * Attribs.NumChannels2)
6257
{
63-
UNEXPECTED("Stride2 is too small. It must be at least ", Width * NumChannels, " bytes long.");
58+
UNEXPECTED("Stride2 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels2, " bytes long.");
6459
return;
6560
}
6661

67-
for (Uint32 row = 0; row < Height; ++row)
62+
const Uint32 NumChannels = std::min(Attribs.NumChannels1, Attribs.NumChannels2);
63+
for (Uint32 row = 0; row < Attribs.Height; ++row)
6864
{
69-
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(pImage1) + row * Stride1;
70-
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(pImage2) + row * Stride2;
65+
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(Attribs.pImage1) + row * Attribs.Stride1;
66+
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(Attribs.pImage2) + row * Attribs.Stride2;
7167

72-
for (Uint32 col = 0; col < Width; ++col)
68+
for (Uint32 col = 0; col < Attribs.Width; ++col)
7369
{
7470
Uint32 PixelDiff = 0;
7571
for (Uint32 ch = 0; ch < NumChannels; ++ch)
7672
{
7773
const Uint32 ChannelDiff = static_cast<Uint32>(
78-
std::abs(static_cast<int>(pRow1[col * NumChannels + ch]) -
79-
static_cast<int>(pRow2[col * NumChannels + ch])));
74+
std::abs(static_cast<int>(pRow1[col * Attribs.NumChannels1 + ch]) -
75+
static_cast<int>(pRow2[col * Attribs.NumChannels2 + ch])));
8076
PixelDiff = std::max(PixelDiff, ChannelDiff);
8177
}
8278

@@ -87,7 +83,7 @@ void GetImageDifference(Uint32 Width,
8783
Diff.RmsDiff += static_cast<float>(PixelDiff * PixelDiff);
8884
Diff.MaxDiff = std::max(Diff.MaxDiff, PixelDiff);
8985

90-
if (PixelDiff > Threshold)
86+
if (PixelDiff > Attribs.Threshold)
9187
{
9288
++Diff.NumDiffPixelsAboveThreshold;
9389
}
@@ -170,17 +166,10 @@ void ComputeDifferenceImage(
170166

171167
extern "C"
172168
{
173-
void Diligent_GetImageDifference(Diligent::Uint32 Width,
174-
Diligent::Uint32 Height,
175-
Diligent::Uint32 NumChannels,
176-
const void* pImage1,
177-
Diligent::Uint32 Stride1,
178-
const void* pImage2,
179-
Diligent::Uint32 Stride2,
180-
Diligent::Uint32 Threshold,
181-
Diligent::ImageDiffInfo& ImageDiff)
169+
void Diligent_GetImageDifference(const Diligent::GetImageDifferenceAttribs& Attribs,
170+
Diligent::ImageDiffInfo& ImageDiff)
182171
{
183-
Diligent::GetImageDifference(Width, Height, NumChannels, pImage1, Stride1, pImage2, Stride2, Threshold, ImageDiff);
172+
Diligent::GetImageDifference(Attribs, ImageDiff);
184173
}
185174

186175
void Diligent_ComputeDifferenceImage(Diligent::Uint32 Width,

Tests/DiligentCoreTest/src/Common/ImageToolsTest.cpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ TEST(Common_ImageTools, GetImageDifference)
4242
constexpr Uint32 Height = 2;
4343
constexpr Uint32 Stride1 = 11;
4444
constexpr Uint32 Stride2 = 12;
45+
constexpr Uint32 Stride3 = 9;
46+
4547
// clang-format off
4648
constexpr char Image1[Stride1 * Height] = {
4749
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20,
@@ -55,11 +57,29 @@ TEST(Common_ImageTools, GetImageDifference)
5557
// ^ ^ ^ ^ ^
5658
// 3 4 5 4 4
5759
};
60+
constexpr char Image3[Stride3 * Height] = {
61+
1, 2, 5, 8, 7, 8, 10, 20, 30,
62+
// ^ ^
63+
// -1 -3
64+
6, 4, 5, 6, 8, 6, 40, 50, 60,
65+
// ^ ^ ^
66+
// 3 4 5
67+
};
5868
// clang-format on
5969

6070
{
71+
GetImageDifferenceAttribs Attribs;
72+
Attribs.Width = Width;
73+
Attribs.Height = Height;
74+
Attribs.pImage1 = Image1;
75+
Attribs.NumChannels1 = 3;
76+
Attribs.Stride1 = Stride1;
77+
Attribs.pImage2 = Image1;
78+
Attribs.NumChannels2 = 3;
79+
Attribs.Stride2 = Stride1;
80+
6181
ImageDiffInfo Diff;
62-
GetImageDifference(Width, Height, 3, Image1, Stride1, Image1, Stride1, 3, Diff);
82+
GetImageDifference(Attribs, Diff);
6383
EXPECT_EQ(Diff.NumDiffPixels, 0);
6484
EXPECT_EQ(Diff.NumDiffPixelsAboveThreshold, 0);
6585
EXPECT_EQ(Diff.MaxDiff, 0);
@@ -68,8 +88,40 @@ TEST(Common_ImageTools, GetImageDifference)
6888
}
6989

7090
{
91+
GetImageDifferenceAttribs Attribs;
92+
Attribs.Width = Width;
93+
Attribs.Height = Height;
94+
Attribs.pImage1 = Image1;
95+
Attribs.NumChannels1 = 3;
96+
Attribs.Stride1 = Stride1;
97+
Attribs.pImage2 = Image2;
98+
Attribs.NumChannels2 = 3;
99+
Attribs.Stride2 = Stride2;
100+
Attribs.Threshold = 3;
101+
102+
ImageDiffInfo Diff;
103+
GetImageDifference(Attribs, Diff);
104+
EXPECT_EQ(Diff.NumDiffPixels, 3);
105+
EXPECT_EQ(Diff.NumDiffPixelsAboveThreshold, 2);
106+
EXPECT_EQ(Diff.MaxDiff, 5);
107+
EXPECT_FLOAT_EQ(Diff.AvgDiff, 4.f);
108+
EXPECT_FLOAT_EQ(Diff.RmsDiff, std::sqrt((9.f + 16.f + 25.f) / 3.f));
109+
}
110+
111+
{
112+
GetImageDifferenceAttribs Attribs;
113+
Attribs.Width = Width;
114+
Attribs.Height = Height;
115+
Attribs.pImage1 = Image1;
116+
Attribs.NumChannels1 = 3;
117+
Attribs.Stride1 = Stride1;
118+
Attribs.pImage2 = Image3;
119+
Attribs.NumChannels2 = 2;
120+
Attribs.Stride2 = Stride3;
121+
Attribs.Threshold = 3;
122+
71123
ImageDiffInfo Diff;
72-
GetImageDifference(Width, Height, 3, Image1, Stride1, Image2, Stride2, 3, Diff);
124+
GetImageDifference(Attribs, Diff);
73125
EXPECT_EQ(Diff.NumDiffPixels, 3);
74126
EXPECT_EQ(Diff.NumDiffPixelsAboveThreshold, 2);
75127
EXPECT_EQ(Diff.MaxDiff, 5);

0 commit comments

Comments
 (0)