Skip to content

Commit 379a8b0

Browse files
Common: added image tools with GetImageDifference function
1 parent 4350541 commit 379a8b0

File tree

7 files changed

+299
-6
lines changed

7 files changed

+299
-6
lines changed

Common/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ set(INTERFACE
2222
interface/FixedBlockMemoryAllocator.hpp
2323
interface/GeometryPrimitives.h
2424
interface/HashUtils.hpp
25+
interface/ImageTools.h
2526
interface/LRUCache.hpp
2627
interface/FixedLinearAllocator.hpp
2728
interface/DynamicLinearAllocator.hpp
@@ -58,6 +59,7 @@ set(SOURCE
5859
src/FileWrapper.cpp
5960
src/FixedBlockMemoryAllocator.cpp
6061
src/GeometryPrimitives.cpp
62+
src/ImageTools.cpp
6163
src/MemoryFileStream.cpp
6264
src/Serializer.cpp
6365
src/SpinLock.cpp

Common/interface/ImageTools.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#pragma once
28+
29+
/// \file
30+
/// Image processing tools
31+
32+
#include "../../Primitives/interface/BasicTypes.h"
33+
34+
35+
DILIGENT_BEGIN_NAMESPACE(Diligent)
36+
37+
#include "../../Primitives/interface/DefineRefMacro.h"
38+
39+
/// Image difference information
40+
struct ImageDiffInfo
41+
{
42+
/// The number of pixels that differ
43+
Uint32 NumDiffPixels DEFAULT_INITIALIZER(0);
44+
45+
/// The number of pixels that differ above the threshold
46+
Uint32 NumDiffPixelsAboveThreshold DEFAULT_INITIALIZER(0);
47+
48+
/// The maximum difference between any two pixels
49+
Uint32 MaxDiff DEFAULT_INITIALIZER(0);
50+
51+
/// The average difference between all pixels, not counting pixels that are equal
52+
float AvgDiff DEFAULT_INITIALIZER(0);
53+
54+
/// The root mean square difference between all pixels, not counting pixels that are equal
55+
float RmsDiff DEFAULT_INITIALIZER(0);
56+
};
57+
typedef struct ImageDiffInfo ImageDiffInfo;
58+
59+
/// Compute the difference between two images
60+
///
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
69+
/// \return The image difference information, see Diligent::ImageDiffInfo.
70+
///
71+
/// \remarks The difference between two pixels is calculated as the maximum of the
72+
/// absolute differences of all channels. The average difference is the
73+
/// average of all differences, not counting pixels that are equal.
74+
/// The root mean square difference is calculated as the square root of
75+
/// the average of the squares of all differences, not counting pixels that
76+
/// 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);
87+
88+
#include "../../Primitives/interface/UndefRefMacro.h"
89+
90+
DILIGENT_END_NAMESPACE // namespace Diligent

Common/src/ImageTools.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#include "ImageTools.h"
28+
29+
#include <algorithm>
30+
#include <cmath>
31+
32+
#include "DebugUtilities.hpp"
33+
34+
namespace Diligent
35+
{
36+
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)
46+
{
47+
Diff = {};
48+
49+
if (pImage1 == nullptr || pImage2 == nullptr)
50+
{
51+
UNEXPECTED("Image pointers cannot be null");
52+
return;
53+
}
54+
55+
if (Stride1 < Width * NumChannels)
56+
{
57+
UNEXPECTED("Stride1 is too small. It must be at least ", Width * NumChannels, " bytes long.");
58+
return;
59+
}
60+
61+
if (Stride2 < Width * NumChannels)
62+
{
63+
UNEXPECTED("Stride2 is too small. It must be at least ", Width * NumChannels, " bytes long.");
64+
return;
65+
}
66+
67+
for (Uint32 row = 0; row < Height; ++row)
68+
{
69+
const Uint8* pRow1 = reinterpret_cast<const Uint8*>(pImage1) + row * Stride1;
70+
const Uint8* pRow2 = reinterpret_cast<const Uint8*>(pImage2) + row * Stride2;
71+
72+
for (Uint32 col = 0; col < Width; ++col)
73+
{
74+
Uint32 PixelDiff = 0;
75+
for (Uint32 ch = 0; ch < NumChannels; ++ch)
76+
{
77+
const Uint32 ChannelDiff = static_cast<Uint32>(
78+
std::abs(static_cast<int>(pRow1[col * NumChannels + ch]) -
79+
static_cast<int>(pRow2[col * NumChannels + ch])));
80+
PixelDiff = std::max(PixelDiff, ChannelDiff);
81+
}
82+
83+
if (PixelDiff != 0)
84+
{
85+
++Diff.NumDiffPixels;
86+
Diff.AvgDiff += static_cast<float>(PixelDiff);
87+
Diff.RmsDiff += static_cast<float>(PixelDiff * PixelDiff);
88+
Diff.MaxDiff = std::max(Diff.MaxDiff, PixelDiff);
89+
90+
if (PixelDiff > Threshold)
91+
{
92+
++Diff.NumDiffPixelsAboveThreshold;
93+
}
94+
}
95+
}
96+
}
97+
98+
if (Diff.NumDiffPixels > 0)
99+
{
100+
Diff.AvgDiff /= static_cast<float>(Diff.NumDiffPixels);
101+
Diff.RmsDiff = std::sqrt(Diff.RmsDiff / static_cast<float>(Diff.NumDiffPixels));
102+
}
103+
}
104+
105+
} // namespace Diligent
106+
107+
extern "C"
108+
{
109+
void Diligent_GetImageDifference(Diligent::Uint32 Width,
110+
Diligent::Uint32 Height,
111+
Diligent::Uint32 NumChannels,
112+
const void* pImage1,
113+
Diligent::Uint32 Stride1,
114+
const void* pImage2,
115+
Diligent::Uint32 Stride2,
116+
Diligent::Uint32 Threshold,
117+
Diligent::ImageDiffInfo& ImageDiff)
118+
{
119+
Diligent::GetImageDifference(Width, Height, NumChannels, pImage1, Stride1, pImage2, Stride2, Threshold, ImageDiff);
120+
}
121+
}

Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -1884,7 +1884,7 @@ BIND_FLAGS SwapChainUsageFlagsToBindFlags(SWAP_CHAIN_USAGE_FLAGS SwapChainUsage)
18841884
break;
18851885

18861886
default:
1887-
UNEXPECTED("Unexpeced swap chain usage flag");
1887+
UNEXPECTED("Unexpected swap chain usage flag");
18881888
}
18891889
}
18901890
return BindFlags;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#include "ImageTools.h"
28+
29+
#include <cmath>
30+
31+
#include "gtest/gtest.h"
32+
33+
using namespace Diligent;
34+
35+
namespace
36+
{
37+
38+
TEST(Common_ImageTools, GetImageDifference)
39+
{
40+
constexpr Uint32 Width = 3;
41+
constexpr Uint32 Height = 2;
42+
constexpr Uint32 Stride1 = 11;
43+
constexpr Uint32 Stride2 = 12;
44+
// clang-format off
45+
constexpr char Image1[Stride1 * Height] = {
46+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20,
47+
9, 8, 7, 5, 6, 4, 3, 2, 1, 30, 40,
48+
};
49+
constexpr char Image2[Stride2 * Height] = {
50+
1, 2, 3, 5, 8, 8, 7, 8, 9, 10, 20, 30,
51+
// ^ ^ ^
52+
// -1 -3 -2
53+
6, 4, 2, 5, 6, 4, 7, 6, 1, 40, 50, 60,
54+
// ^ ^ ^ ^ ^
55+
// 3 4 5 4 4
56+
};
57+
// clang-format on
58+
59+
{
60+
ImageDiffInfo Diff;
61+
GetImageDifference(Width, Height, 3, Image1, Stride1, Image1, Stride1, 3, Diff);
62+
EXPECT_EQ(Diff.NumDiffPixels, 0);
63+
EXPECT_EQ(Diff.NumDiffPixelsAboveThreshold, 0);
64+
EXPECT_EQ(Diff.MaxDiff, 0);
65+
EXPECT_EQ(Diff.AvgDiff, 0.f);
66+
EXPECT_EQ(Diff.RmsDiff, 0.f);
67+
}
68+
69+
{
70+
ImageDiffInfo Diff;
71+
GetImageDifference(Width, Height, 3, Image1, Stride1, Image2, Stride2, 3, Diff);
72+
EXPECT_EQ(Diff.NumDiffPixels, 3);
73+
EXPECT_EQ(Diff.NumDiffPixelsAboveThreshold, 2);
74+
EXPECT_EQ(Diff.MaxDiff, 5);
75+
EXPECT_FLOAT_EQ(Diff.AvgDiff, 4.f);
76+
EXPECT_FLOAT_EQ(Diff.RmsDiff, std::sqrt((9.f + 16.f + 25.f) / 3.f));
77+
}
78+
}
79+
80+
} // namespace

Tests/DiligentCoreTest/src/Common/ParsingToolsTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -345,7 +345,7 @@ TEST(Common_ParsingTools, SkipString)
345345
Test("abc", "ab", true);
346346
Test("abc", "ad", false);
347347
Test("abc", "abc", true);
348-
Test("abc", "abd", false);
348+
Test("abc", "abx", false);
349349
Test("abc", "abcd", false);
350350
}
351351

Tests/DiligentCoreTest/src/Common/StringToolsTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,7 +41,7 @@ TEST(Common_StringTools, StreqSuff)
4141
EXPECT_TRUE(!StreqSuff("ab", "abc", "_def"));
4242
EXPECT_TRUE(!StreqSuff("abc_de", "abc", "_def"));
4343
EXPECT_TRUE(!StreqSuff("abc_def", "ab", "_def"));
44-
EXPECT_TRUE(!StreqSuff("abc_def", "abd", "_def"));
44+
EXPECT_TRUE(!StreqSuff("abc_def", "abx", "_def"));
4545
EXPECT_TRUE(!StreqSuff("abc_def", "abc", "_de"));
4646
EXPECT_TRUE(!StreqSuff("abc", "abc", "_def"));
4747
EXPECT_TRUE(!StreqSuff("abc_def", "", "_def"));

0 commit comments

Comments
 (0)