Skip to content

Commit bc41c1d

Browse files
Image tools: reworked ComputeDifferenceImage function
1 parent c17267f commit bc41c1d

File tree

3 files changed

+186
-77
lines changed

3 files changed

+186
-77
lines changed

Common/interface/ImageTools.h

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ struct GetImageDifferenceAttribs
8989
};
9090
typedef struct GetImageDifferenceAttribs GetImageDifferenceAttribs;
9191

92-
/// Compute the difference between two images
92+
/// Computes the difference between two images
9393
///
9494
/// \param [in] Attribs Image difference attributes, see Diligent::GetImageDifferenceAttribs.
9595
///
@@ -104,33 +104,52 @@ typedef struct GetImageDifferenceAttribs GetImageDifferenceAttribs;
104104
void DILIGENT_GLOBAL_FUNCTION(GetImageDifference)(const GetImageDifferenceAttribs REF Attribs, ImageDiffInfo REF ImageDiff);
105105

106106

107-
// clang-format off
108-
/// Compute the difference image
107+
/// Attributes for ComputeDifferenceImage function
108+
struct ComputeDifferenceImageAttribs
109+
{
110+
/// Image width
111+
Uint32 Width DEFAULT_INITIALIZER(0);
112+
113+
/// Image height
114+
Uint32 Height DEFAULT_INITIALIZER(0);
115+
116+
/// A pointer to the first image data
117+
const void* pImage1 DEFAULT_INITIALIZER(nullptr);
118+
119+
/// Number of channels in the first image
120+
Uint32 NumChannels1 DEFAULT_INITIALIZER(0);
121+
122+
/// Row stride of the first image data, in bytes
123+
Uint32 Stride1 DEFAULT_INITIALIZER(0);
124+
125+
/// A pointer to the second image data
126+
const void* pImage2 DEFAULT_INITIALIZER(nullptr);
127+
128+
/// Number of channels in the second image
129+
Uint32 NumChannels2 DEFAULT_INITIALIZER(0);
130+
131+
/// Row stride of the second image data, in bytes
132+
Uint32 Stride2 DEFAULT_INITIALIZER(0);
133+
134+
/// A pointer to the difference image data
135+
void* pDiffImage DEFAULT_INITIALIZER(nullptr);
136+
137+
/// Row stride of the difference image data, in bytes
138+
Uint32 DiffStride DEFAULT_INITIALIZER(0);
139+
140+
/// Number of channels in the difference image.
141+
/// If 0, the number of channels will be the same as in the input images.
142+
Uint32 NumDiffChannels DEFAULT_INITIALIZER(0);
143+
144+
/// Scale factor for the difference image
145+
float Scale DEFAULT_INITIALIZER(1.f);
146+
};
147+
typedef struct ComputeDifferenceImageAttribs ComputeDifferenceImageAttribs;
148+
149+
/// Computes the difference image
109150
///
110-
/// \param [in] Width Image width
111-
/// \param [in] Height Image height
112-
/// \param [in] NumChannels Number of channels in the image
113-
/// \param [in] pImage1 Pointer to the first image data
114-
/// \param [in] Stride1 Row stride of the first image data, in bytes
115-
/// \param [in] pImage2 Pointer to the second image data
116-
/// \param [in] Stride2 Row stride of the second image data, in bytes
117-
/// \param [out] pDiffImage Pointer to the difference image data
118-
/// \param [in] DiffStride Row stride of the difference image data, in bytes
119-
/// \param [in] NumDiffChannels Number of channels in the difference image.
120-
/// If 0, the number of channels will be the same as in the input images.
121-
/// \param [in] Scale Scale factor for the difference image
122-
void DILIGENT_GLOBAL_FUNCTION(ComputeDifferenceImage)(
123-
Uint32 Width,
124-
Uint32 Height,
125-
Uint32 NumChannels,
126-
const void* pImage1,
127-
Uint32 Stride1,
128-
const void* pImage2,
129-
Uint32 Stride2,
130-
void* pDiffImage,
131-
Uint32 DiffStride,
132-
Uint32 NumDiffChannels DEFAULT_INITIALIZER(0),
133-
float Scale DEFAULT_INITIALIZER(1.f));
151+
/// \param [in] Attribs Compute difference image attributes, see Diligent::ComputeDifferenceImageAttribs.
152+
void DILIGENT_GLOBAL_FUNCTION(ComputeDifferenceImage)(const ComputeDifferenceImageAttribs REF Attribs);
134153
// clang-format on
135154

136155
#include "../../Primitives/interface/UndefRefMacro.h"

Common/src/ImageTools.cpp

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,23 @@ void GetImageDifference(const GetImageDifferenceAttribs& Attribs,
4545
return;
4646
}
4747

48-
VERIFY(Attribs.NumChannels1 != 0, "NumChannels1 cannot be zero");
48+
if (Attribs.NumChannels1 == 0)
49+
{
50+
UNEXPECTED("NumChannels1 cannot be zero");
51+
return;
52+
}
53+
4954
if (Attribs.Stride1 < Attribs.Width * Attribs.NumChannels1)
5055
{
5156
UNEXPECTED("Stride1 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels1, " bytes long.");
5257
return;
5358
}
5459

55-
VERIFY(Attribs.NumChannels2 != 0, "NumChannels2 cannot be zero");
60+
if (Attribs.NumChannels2 == 0)
61+
{
62+
UNEXPECTED("NumChannels2 cannot be zero");
63+
return;
64+
}
5665
if (Attribs.Stride2 < Attribs.Width * Attribs.NumChannels2)
5766
{
5867
UNEXPECTED("Stride2 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels2, " bytes long.");
@@ -98,63 +107,60 @@ void GetImageDifference(const GetImageDifferenceAttribs& Attribs,
98107
}
99108
}
100109

101-
void ComputeDifferenceImage(
102-
Uint32 Width,
103-
Uint32 Height,
104-
Uint32 NumChannels,
105-
const void* pImage1,
106-
Uint32 Stride1,
107-
const void* pImage2,
108-
Uint32 Stride2,
109-
void* pDiffImage,
110-
Uint32 DiffStride,
111-
Uint32 NumDiffChannels,
112-
float Scale)
110+
void ComputeDifferenceImage(const ComputeDifferenceImageAttribs& Attribs)
113111
{
114-
if (pImage1 == nullptr || pImage2 == nullptr || pDiffImage == nullptr)
112+
if (Attribs.pImage1 == nullptr || Attribs.pImage2 == nullptr || Attribs.pDiffImage == nullptr)
115113
{
116114
UNEXPECTED("Image pointers cannot be null");
117115
return;
118116
}
119117

120-
if (Stride1 < Width * NumChannels)
118+
if (Attribs.NumChannels1 == 0)
121119
{
122-
UNEXPECTED("Stride1 is too small. It must be at least ", Width * NumChannels, " bytes long.");
120+
UNEXPECTED("NumChannels1 cannot be zero");
123121
return;
124122
}
125-
126-
if (Stride2 < Width * NumChannels)
123+
if (Attribs.Stride1 < Attribs.Width * Attribs.NumChannels1)
127124
{
128-
UNEXPECTED("Stride2 is too small. It must be at least ", Width * NumChannels, " bytes long.");
125+
UNEXPECTED("Stride1 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels1, " bytes long.");
129126
return;
130127
}
131128

132-
if (DiffStride < Width * NumDiffChannels)
129+
if (Attribs.NumChannels2 == 0)
133130
{
134-
UNEXPECTED("DiffStride is too small. It must be at least ", Width * NumDiffChannels, " bytes long.");
131+
UNEXPECTED("NumChannels2 cannot be zero");
132+
return;
133+
}
134+
if (Attribs.Stride2 < Attribs.Width * Attribs.NumChannels2)
135+
{
136+
UNEXPECTED("Stride2 is too small. It must be at least ", Attribs.Width * Attribs.NumChannels2, " bytes long.");
135137
return;
136138
}
137139

138-
if (NumDiffChannels == 0)
140+
const Uint32 NumSrcChannels = std::min(Attribs.NumChannels1, Attribs.NumChannels2);
141+
const Uint32 NumDiffChannels = Attribs.NumDiffChannels != 0 ? Attribs.NumDiffChannels : NumSrcChannels;
142+
if (Attribs.DiffStride < Attribs.Width * NumDiffChannels)
139143
{
140-
NumDiffChannels = NumChannels;
144+
UNEXPECTED("DiffStride is too small. It must be at least ", Attribs.Width * NumDiffChannels, " bytes long.");
145+
return;
141146
}
142147

143-
for (Uint32 row = 0; row < Height; ++row)
148+
for (Uint32 row = 0; row < Attribs.Height; ++row)
144149
{
145-
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(pImage1) + row * Stride1;
146-
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(pImage2) + row * Stride2;
147-
Uint8* pDiffRow = reinterpret_cast<Uint8*>(pDiffImage) + row * DiffStride;
150+
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(Attribs.pImage1) + row * Attribs.Stride1;
151+
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(Attribs.pImage2) + row * Attribs.Stride2;
152+
Uint8* pDiffRow = reinterpret_cast<Uint8*>(Attribs.pDiffImage) + row * Attribs.DiffStride;
148153

149-
for (Uint32 col = 0; col < Width; ++col)
154+
for (Uint32 col = 0; col < Attribs.Width; ++col)
150155
{
151156
for (Uint32 ch = 0; ch < NumDiffChannels; ++ch)
152157
{
153158
int ChannelDiff = ch == 3 ? 255 : 0;
154-
if (ch < NumChannels)
159+
if (ch < NumSrcChannels)
155160
{
156-
ChannelDiff = std::abs(static_cast<int>(pRow1[col * NumChannels + ch]) - static_cast<int>(pRow2[col * NumChannels + ch]));
157-
ChannelDiff = std::min(255, static_cast<int>(ChannelDiff * Scale));
161+
ChannelDiff = std::abs(static_cast<int>(pRow1[col * Attribs.NumChannels1 + ch]) -
162+
static_cast<int>(pRow2[col * Attribs.NumChannels2 + ch]));
163+
ChannelDiff = std::min(255, static_cast<int>(ChannelDiff * Attribs.Scale));
158164
}
159165
pDiffRow[col * NumDiffChannels + ch] = static_cast<Uint8>(ChannelDiff);
160166
}
@@ -172,18 +178,8 @@ extern "C"
172178
Diligent::GetImageDifference(Attribs, ImageDiff);
173179
}
174180

175-
void Diligent_ComputeDifferenceImage(Diligent::Uint32 Width,
176-
Diligent::Uint32 Height,
177-
Diligent::Uint32 NumChannels,
178-
const void* pImage1,
179-
Diligent::Uint32 Stride1,
180-
const void* pImage2,
181-
Diligent::Uint32 Stride2,
182-
void* pDiffImage,
183-
Diligent::Uint32 DiffStride,
184-
Diligent::Uint32 NumDiffChannels,
185-
float Scale)
181+
void Diligent_ComputeDifferenceImage(const Diligent::ComputeDifferenceImageAttribs& Attribs)
186182
{
187-
Diligent::ComputeDifferenceImage(Width, Height, NumChannels, pImage1, Stride1, pImage2, Stride2, pDiffImage, DiffStride, NumDiffChannels, Scale);
183+
Diligent::ComputeDifferenceImage(Attribs);
188184
}
189185
}

Tests/DiligentCoreTest/src/Common/ImageToolsTest.cpp

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ TEST(Common_ImageTools, GetImageDifference)
6262
// ^ ^
6363
// -1 -3
6464
6, 4, 5, 6, 8, 6, 40, 50, 60,
65-
// ^ ^ ^
66-
// 3 4 5
65+
// ^ ^ ^ ^
66+
// 3 4 5 4
6767
};
6868
// clang-format on
6969

@@ -136,6 +136,8 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
136136
constexpr Uint32 Height = 2;
137137
constexpr Uint32 Stride1 = 11;
138138
constexpr Uint32 Stride2 = 12;
139+
constexpr Uint32 Stride3 = 9;
140+
139141
// clang-format off
140142
constexpr char Image1[Stride1 * Height] = {
141143
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20,
@@ -149,6 +151,14 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
149151
// ^ ^ ^ ^ ^
150152
// 3 4 5 4 4
151153
};
154+
constexpr char Image3[Stride3 * Height] = {
155+
1, 2, 5, 8, 7, 8, 10, 20, 30,
156+
// ^ ^
157+
// -1 -3
158+
6, 4, 5, 6, 8, 6, 40, 50, 60,
159+
// ^ ^ ^ ^
160+
// 3 4 5 4
161+
};
152162
// clang-format on
153163

154164
{
@@ -158,8 +168,21 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
158168
3, 4, 5, 0, 0, 0, 4, 4, 0,
159169
};
160170
// clang-format on
171+
161172
std::array<Uint8, Width * Height * 3> DiffImage{};
162-
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 3);
173+
174+
ComputeDifferenceImageAttribs Attribs;
175+
Attribs.Width = Width;
176+
Attribs.Height = Height;
177+
Attribs.pImage1 = Image1;
178+
Attribs.NumChannels1 = 3;
179+
Attribs.Stride1 = Stride1;
180+
Attribs.pImage2 = Image2;
181+
Attribs.NumChannels2 = 3;
182+
Attribs.Stride2 = Stride2;
183+
Attribs.pDiffImage = DiffImage.data();
184+
Attribs.DiffStride = Width * 3;
185+
ComputeDifferenceImage(Attribs);
163186
EXPECT_EQ(DiffImage, RefDiffImage);
164187
}
165188

@@ -171,8 +194,22 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
171194
3, 4, 5, 255, 0, 0, 0, 255, 4, 4, 0, 255,
172195
};
173196
// clang-format on
197+
174198
std::array<Uint8, Width * Height * 4> DiffImage{};
175-
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 4, 4);
199+
200+
ComputeDifferenceImageAttribs Attribs;
201+
Attribs.Width = Width;
202+
Attribs.Height = Height;
203+
Attribs.pImage1 = Image1;
204+
Attribs.NumChannels1 = 3;
205+
Attribs.Stride1 = Stride1;
206+
Attribs.pImage2 = Image2;
207+
Attribs.NumChannels2 = 3;
208+
Attribs.Stride2 = Stride2;
209+
Attribs.pDiffImage = DiffImage.data();
210+
Attribs.NumDiffChannels = 4;
211+
Attribs.DiffStride = Width * 4;
212+
ComputeDifferenceImage(Attribs);
176213
EXPECT_EQ(DiffImage, RefDiffImage);
177214
}
178215

@@ -184,8 +221,22 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
184221
3, 4, 0, 0, 4, 4,
185222
};
186223
// clang-format on
224+
187225
std::array<Uint8, Width * Height * 2> DiffImage{};
188-
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 2, 2);
226+
227+
ComputeDifferenceImageAttribs Attribs;
228+
Attribs.Width = Width;
229+
Attribs.Height = Height;
230+
Attribs.pImage1 = Image1;
231+
Attribs.NumChannels1 = 3;
232+
Attribs.Stride1 = Stride1;
233+
Attribs.pImage2 = Image2;
234+
Attribs.NumChannels2 = 3;
235+
Attribs.Stride2 = Stride2;
236+
Attribs.pDiffImage = DiffImage.data();
237+
Attribs.NumDiffChannels = 2;
238+
Attribs.DiffStride = Width * 2;
239+
ComputeDifferenceImage(Attribs);
189240
EXPECT_EQ(DiffImage, RefDiffImage);
190241
}
191242

@@ -197,8 +248,51 @@ TEST(Common_ImageTools, ComputeDifferenceImage)
197248
6, 8, 10, 255, 0, 0, 0, 255, 8, 8, 0, 255,
198249
};
199250
// clang-format on
251+
200252
std::array<Uint8, Width * Height * 4> DiffImage{};
201-
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 4, 4, 2.f);
253+
254+
ComputeDifferenceImageAttribs Attribs;
255+
Attribs.Width = Width;
256+
Attribs.Height = Height;
257+
Attribs.pImage1 = Image1;
258+
Attribs.NumChannels1 = 3;
259+
Attribs.Stride1 = Stride1;
260+
Attribs.pImage2 = Image2;
261+
Attribs.NumChannels2 = 3;
262+
Attribs.Stride2 = Stride2;
263+
Attribs.pDiffImage = DiffImage.data();
264+
Attribs.NumDiffChannels = 4;
265+
Attribs.DiffStride = Width * 4;
266+
Attribs.Scale = 2.f;
267+
ComputeDifferenceImage(Attribs);
268+
EXPECT_EQ(DiffImage, RefDiffImage);
269+
}
270+
271+
// 3 vs 2 channels -> 4 channels + scale
272+
{
273+
// clang-format off
274+
constexpr std::array<Uint8, Width * Height * 4> RefDiffImage = {
275+
0, 0, 0, 255, 2, 6, 0, 255, 0, 0, 0, 255,
276+
6, 8, 0, 255, 0, 0, 0, 255, 10, 8, 0, 255,
277+
};
278+
// clang-format on
279+
280+
std::array<Uint8, Width * Height * 4> DiffImage{};
281+
282+
ComputeDifferenceImageAttribs Attribs;
283+
Attribs.Width = Width;
284+
Attribs.Height = Height;
285+
Attribs.pImage1 = Image1;
286+
Attribs.NumChannels1 = 3;
287+
Attribs.Stride1 = Stride1;
288+
Attribs.pImage2 = Image3;
289+
Attribs.NumChannels2 = 2;
290+
Attribs.Stride2 = Stride3;
291+
Attribs.pDiffImage = DiffImage.data();
292+
Attribs.NumDiffChannels = 4;
293+
Attribs.DiffStride = Width * 4;
294+
Attribs.Scale = 2.f;
295+
ComputeDifferenceImage(Attribs);
202296
EXPECT_EQ(DiffImage, RefDiffImage);
203297
}
204298
}

0 commit comments

Comments
 (0)