Skip to content

Commit 7039a2a

Browse files
Image tools: added ComputeDifferenceImage function
1 parent 379a8b0 commit 7039a2a

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed

Common/interface/ImageTools.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,36 @@ void DILIGENT_GLOBAL_FUNCTION(GetImageDifference)(
8585
Uint32 Threshold,
8686
ImageDiffInfo REF ImageDiff);
8787

88+
89+
// clang-format off
90+
/// Compute the difference image
91+
///
92+
/// \param [in] Width Image width
93+
/// \param [in] Height Image height
94+
/// \param [in] NumChannels Number of channels in the image
95+
/// \param [in] pImage1 Pointer to the first image data
96+
/// \param [in] Stride1 Row stride of the first image data, in bytes
97+
/// \param [in] pImage2 Pointer to the second image data
98+
/// \param [in] Stride2 Row stride of the second image data, in bytes
99+
/// \param [out] pDiffImage Pointer to the difference image data
100+
/// \param [in] DiffStride Row stride of the difference image data, in bytes
101+
/// \param [in] NumDiffChannels Number of channels in the difference image.
102+
/// If 0, the number of channels will be the same as in the input images.
103+
/// \param [in] Scale Scale factor for the difference image
104+
void DILIGENT_GLOBAL_FUNCTION(ComputeDifferenceImage)(
105+
Uint32 Width,
106+
Uint32 Height,
107+
Uint32 NumChannels,
108+
const void* pImage1,
109+
Uint32 Stride1,
110+
const void* pImage2,
111+
Uint32 Stride2,
112+
void* pDiffImage,
113+
Uint32 DiffStride,
114+
Uint32 NumDiffChannels DEFAULT_INITIALIZER(0),
115+
float Scale DEFAULT_INITIALIZER(1.f));
116+
// clang-format on
117+
88118
#include "../../Primitives/interface/UndefRefMacro.h"
89119

90120
DILIGENT_END_NAMESPACE // namespace Diligent

Common/src/ImageTools.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,70 @@ void GetImageDifference(Uint32 Width,
102102
}
103103
}
104104

105+
void ComputeDifferenceImage(
106+
Uint32 Width,
107+
Uint32 Height,
108+
Uint32 NumChannels,
109+
const void* pImage1,
110+
Uint32 Stride1,
111+
const void* pImage2,
112+
Uint32 Stride2,
113+
void* pDiffImage,
114+
Uint32 DiffStride,
115+
Uint32 NumDiffChannels,
116+
float Scale)
117+
{
118+
if (pImage1 == nullptr || pImage2 == nullptr || pDiffImage == nullptr)
119+
{
120+
UNEXPECTED("Image pointers cannot be null");
121+
return;
122+
}
123+
124+
if (Stride1 < Width * NumChannels)
125+
{
126+
UNEXPECTED("Stride1 is too small. It must be at least ", Width * NumChannels, " bytes long.");
127+
return;
128+
}
129+
130+
if (Stride2 < Width * NumChannels)
131+
{
132+
UNEXPECTED("Stride2 is too small. It must be at least ", Width * NumChannels, " bytes long.");
133+
return;
134+
}
135+
136+
if (DiffStride < Width * NumDiffChannels)
137+
{
138+
UNEXPECTED("DiffStride is too small. It must be at least ", Width * NumDiffChannels, " bytes long.");
139+
return;
140+
}
141+
142+
if (NumDiffChannels == 0)
143+
{
144+
NumDiffChannels = NumChannels;
145+
}
146+
147+
for (Uint32 row = 0; row < Height; ++row)
148+
{
149+
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(pImage1) + row * Stride1;
150+
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(pImage2) + row * Stride2;
151+
Uint8* pDiffRow = reinterpret_cast<Uint8*>(pDiffImage) + row * DiffStride;
152+
153+
for (Uint32 col = 0; col < Width; ++col)
154+
{
155+
for (Uint32 ch = 0; ch < NumDiffChannels; ++ch)
156+
{
157+
int ChannelDiff = ch == 3 ? 255 : 0;
158+
if (ch < NumChannels)
159+
{
160+
ChannelDiff = std::abs(static_cast<int>(pRow1[col * NumChannels + ch]) - static_cast<int>(pRow2[col * NumChannels + ch]));
161+
ChannelDiff = std::min(255, static_cast<int>(ChannelDiff * Scale));
162+
}
163+
pDiffRow[col * NumDiffChannels + ch] = static_cast<Uint8>(ChannelDiff);
164+
}
165+
}
166+
}
167+
}
168+
105169
} // namespace Diligent
106170

107171
extern "C"
@@ -118,4 +182,19 @@ extern "C"
118182
{
119183
Diligent::GetImageDifference(Width, Height, NumChannels, pImage1, Stride1, pImage2, Stride2, Threshold, ImageDiff);
120184
}
185+
186+
void Diligent_ComputeDifferenceImage(Diligent::Uint32 Width,
187+
Diligent::Uint32 Height,
188+
Diligent::Uint32 NumChannels,
189+
const void* pImage1,
190+
Diligent::Uint32 Stride1,
191+
const void* pImage2,
192+
Diligent::Uint32 Stride2,
193+
void* pDiffImage,
194+
Diligent::Uint32 DiffStride,
195+
Diligent::Uint32 NumDiffChannels,
196+
float Scale)
197+
{
198+
Diligent::ComputeDifferenceImage(Width, Height, NumChannels, pImage1, Stride1, pImage2, Stride2, pDiffImage, DiffStride, NumDiffChannels, Scale);
199+
}
121200
}

Tests/DiligentCoreTest/src/Common/ImageToolsTest.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <cmath>
3030

3131
#include "gtest/gtest.h"
32+
#include <array>
3233

3334
using namespace Diligent;
3435

@@ -77,4 +78,77 @@ TEST(Common_ImageTools, GetImageDifference)
7778
}
7879
}
7980

81+
TEST(Common_ImageTools, ComputeDifferenceImage)
82+
{
83+
constexpr Uint32 Width = 3;
84+
constexpr Uint32 Height = 2;
85+
constexpr Uint32 Stride1 = 11;
86+
constexpr Uint32 Stride2 = 12;
87+
// clang-format off
88+
constexpr char Image1[Stride1 * Height] = {
89+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20,
90+
9, 8, 7, 5, 6, 4, 3, 2, 1, 30, 40,
91+
};
92+
constexpr char Image2[Stride2 * Height] = {
93+
1, 2, 3, 5, 8, 8, 7, 8, 9, 10, 20, 30,
94+
// ^ ^ ^
95+
// -1 -3 -2
96+
6, 4, 2, 5, 6, 4, 7, 6, 1, 40, 50, 60,
97+
// ^ ^ ^ ^ ^
98+
// 3 4 5 4 4
99+
};
100+
// clang-format on
101+
102+
{
103+
// clang-format off
104+
constexpr std::array<Uint8, Width * Height * 3> RefDiffImage = {
105+
0, 0, 0, 1, 3, 2, 0, 0, 0,
106+
3, 4, 5, 0, 0, 0, 4, 4, 0,
107+
};
108+
// clang-format on
109+
std::array<Uint8, Width * Height * 3> DiffImage{};
110+
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 3);
111+
EXPECT_EQ(DiffImage, RefDiffImage);
112+
}
113+
114+
// 3 channels -> 4 channels
115+
{
116+
// clang-format off
117+
constexpr std::array<Uint8, Width * Height * 4> RefDiffImage = {
118+
0, 0, 0, 255, 1, 3, 2, 255, 0, 0, 0, 255,
119+
3, 4, 5, 255, 0, 0, 0, 255, 4, 4, 0, 255,
120+
};
121+
// clang-format on
122+
std::array<Uint8, Width * Height * 4> DiffImage{};
123+
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 4, 4);
124+
EXPECT_EQ(DiffImage, RefDiffImage);
125+
}
126+
127+
// 3 channels -> 2 channels
128+
{
129+
// clang-format off
130+
constexpr std::array<Uint8, Width * Height * 2> RefDiffImage = {
131+
0, 0, 1, 3, 0, 0,
132+
3, 4, 0, 0, 4, 4,
133+
};
134+
// clang-format on
135+
std::array<Uint8, Width * Height * 2> DiffImage{};
136+
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 2, 2);
137+
EXPECT_EQ(DiffImage, RefDiffImage);
138+
}
139+
140+
// 3 channels -> 4 channels + scale
141+
{
142+
// clang-format off
143+
constexpr std::array<Uint8, Width * Height * 4> RefDiffImage = {
144+
0, 0, 0, 255, 2, 6, 4, 255, 0, 0, 0, 255,
145+
6, 8, 10, 255, 0, 0, 0, 255, 8, 8, 0, 255,
146+
};
147+
// clang-format on
148+
std::array<Uint8, Width * Height * 4> DiffImage{};
149+
ComputeDifferenceImage(Width, Height, 3, Image1, Stride1, Image2, Stride2, DiffImage.data(), Width * 4, 4, 2.f);
150+
EXPECT_EQ(DiffImage, RefDiffImage);
151+
}
152+
}
153+
80154
} // namespace

0 commit comments

Comments
 (0)