Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions YUViewLib/src/video/rgb/ConversionDifferenceRGB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,27 +124,39 @@ calculateDifferencePredefinedPixelFormat(const InputFrameParameters &frame1,
dst += 4;
}

return {outputImage, sse.getMSE()};
return {outputImage, sse.getMSE(false)};
}

template <typename T>
rgba_t getRGBAndConvertEndianness(const DataPointers<T> dataPointers, const Endianness endianness)
rgba_t getRGBAndConvertEndianness(const DataPointers<T> dataPointers,
const PixelFormatRGB &pixelFormat)
{
constexpr auto bitDepth =
(std::is_same_v<T, uint8_t> ? 8 : (std::is_same_v<T, uint16_t> ? 16 : 32));

auto r = *dataPointers.r;
auto g = *dataPointers.g;
auto b = *dataPointers.b;
T a = 0;

if (endianness == Endianness::Big)
if (pixelFormat.getEndianness() == Endianness::Big)
{
r = swapBytesEndianness<bitDepth>(r);
g = swapBytesEndianness<bitDepth>(g);
b = swapBytesEndianness<bitDepth>(b);
}

return rgba_t({.r = static_cast<int>(r), .g = static_cast<int>(g), .b = static_cast<int>(b)});
if (pixelFormat.hasAlpha())
{
a = *dataPointers.a;
if (pixelFormat.getEndianness() == Endianness::Big)
a = swapBytesEndianness<bitDepth>(a);
}

return rgba_t({.r = static_cast<int>(r),
.g = static_cast<int>(g),
.b = static_cast<int>(b),
.a = static_cast<int>(a)});
}

template <typename T>
Expand All @@ -163,9 +175,9 @@ std::pair<QImage, MSE> calculateDifferenceAndMSE(const InputFrameParameters &fra
calculatePointersToStartOfComponents<T>(frame2.rawDataItem, frame2.frameSize, pixelFormat);

const auto frameSize = Size(std::min(frame1.frameSize.width, frame2.frameSize.width),
std::min(frame1.frameSize.height, frame2.frameSize.height));
std::min(frame1.frameSize.height, frame2.frameSize.height));
auto outputImage = QImage(QSize(frameSize.width, frameSize.height),
functionsGui::platformImageFormat(pixelFormat.hasAlpha()));
functionsGui::platformImageFormat(pixelFormat.hasAlpha()));
SSE sse;

unsigned char *restrict dst = outputImage.bits();
Expand All @@ -174,8 +186,8 @@ std::pair<QImage, MSE> calculateDifferenceAndMSE(const InputFrameParameters &fra

for (unsigned i = 0; i < frameSize.width * frameSize.height; ++i)
{
const auto rgb1 = getRGBAndConvertEndianness(dataPointers1, pixelFormat.getEndianness());
const auto rgb2 = getRGBAndConvertEndianness(dataPointers2, pixelFormat.getEndianness());
const auto rgb1 = getRGBAndConvertEndianness(dataPointers1, pixelFormat);
const auto rgb2 = getRGBAndConvertEndianness(dataPointers2, pixelFormat);

const auto delta = rgb1 - rgb2;

Expand All @@ -190,11 +202,16 @@ std::pair<QImage, MSE> calculateDifferenceAndMSE(const InputFrameParameters &fra
dst += 4;
}

return {outputImage, sse.getMSE()};
return {outputImage, sse.getMSE(pixelFormat.hasAlpha())};
}

} // namespace

void PrintTo(const MSE &mse, std::ostream *os)
{
*os << "MSE(r=" << mse.r << ", g=" << mse.g << ", b=" << mse.b << ", a=" << mse.a << ")";
}

std::pair<QImage, MSE> calculateDifferenceAndMSE(const InputFrameParameters &frame1,
const InputFrameParameters &frame2,
const PixelFormatRGB &pixelFormat,
Expand Down
10 changes: 7 additions & 3 deletions YUViewLib/src/video/rgb/ConversionDifferenceRGB.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include <QByteArray>
#include <QImage>

#include <ostream>

namespace video::rgb
{

Expand All @@ -55,10 +57,12 @@ struct MSE

bool operator==(const MSE &other) const
{
return std::tie(r, g, b, a) == std::tie(other.r, other.g, other.b, a);
return std::tie(r, g, b, a) == std::tie(other.r, other.g, other.b, other.a);
}
};

void PrintTo(const MSE &mse, std::ostream *os);

// Sum of Squared Errors
class SSE
{
Expand All @@ -72,13 +76,13 @@ class SSE
++this->nrSamples;
}

MSE getMSE() const
MSE getMSE(const bool hasAlpha) const
{
MSE mse;
mse.r = static_cast<double>(this->r) / this->nrSamples;
mse.g = static_cast<double>(this->g) / this->nrSamples;
mse.b = static_cast<double>(this->b) / this->nrSamples;
mse.a = static_cast<double>(this->a) / this->nrSamples;
mse.a = hasAlpha ? static_cast<double>(this->a) / this->nrSamples : 0.0;
return mse;
}

Expand Down
27 changes: 20 additions & 7 deletions YUViewLib/src/video/rgb/ConversionFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,17 @@ namespace video::rgb

template <typename T> struct DataPointers
{
const T *r;
const T *g;
const T *b;
const T *r{};
const T *g{};
const T *b{};
const T *a{};

DataPointers operator+=(const int offset)
{
this->r += offset;
this->g += offset;
this->b += offset;
this->a += offset;
return *this;
}
};
Expand All @@ -69,19 +71,30 @@ DataPointers<T> calculatePointersToStartOfComponents(const QByteArray &rawFr
const auto posR = pixelFormat.getChannelPosition(Channel::Red);
const auto posG = pixelFormat.getChannelPosition(Channel::Green);
const auto posB = pixelFormat.getChannelPosition(Channel::Blue);
const auto posA = pixelFormat.getChannelPosition(Channel::Alpha);

const auto castDataPointer = reinterpret_cast<T const *>(rawFrameData.data());

DataPointers<T> dataPointers;
if (pixelFormat.getDataLayout() == DataLayout::Planar)
{
const auto offsetToNextPlane = frameSize.width * frameSize.height;

return {.r = castDataPointer + (posR * offsetToNextPlane),
.g = castDataPointer + (posG * offsetToNextPlane),
.b = castDataPointer + (posB * offsetToNextPlane)};
dataPointers.r = castDataPointer + (posR * offsetToNextPlane);
dataPointers.g = castDataPointer + (posG * offsetToNextPlane);
dataPointers.b = castDataPointer + (posB * offsetToNextPlane);
dataPointers.a =
pixelFormat.hasAlpha() ? castDataPointer + (posA * offsetToNextPlane) : nullptr;
}
else
{
dataPointers.r = castDataPointer + posR;
dataPointers.g = castDataPointer + posG;
dataPointers.b = castDataPointer + posB;
dataPointers.a = pixelFormat.hasAlpha() ? castDataPointer + posA : nullptr;
}

return {.r = castDataPointer + posR, .g = castDataPointer + posG, .b = castDataPointer + posB};
return dataPointers;
}

inline rgba_t extractRGB565Value(const unsigned char *data, const Endianness endianness)
Expand Down
11 changes: 6 additions & 5 deletions YUViewUnitTest/video/rgb/ConversionDifferenceRGBTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ FrameAandB createTestFrameDataRGB565()
using ExpectedImageAndMse = std::pair<QImage, MSE>;
ExpectedImageAndMse generateExpectedImageAndMse(const FrameAandB &testFrames,
const int amplificationFactor,
bool markDifference)
bool markDifference,
bool hasAlpha)
{
QImage image(QSize(TEST_FRAME_SIZE.width, TEST_FRAME_SIZE.height),
functionsGui::platformImageFormat(false));
Expand All @@ -159,7 +160,7 @@ ExpectedImageAndMse generateExpectedImageAndMse(const FrameAandB &testFrames,
const auto &pixelA = testFrames.first.at(i);
const auto &pixelB = testFrames.second.at(i);

const auto diff = pixelA - pixelB;
auto diff = pixelA - pixelB;

sse.addSample(diff);

Expand All @@ -177,7 +178,7 @@ ExpectedImageAndMse generateExpectedImageAndMse(const FrameAandB &testFrames,
image.setPixel(x, y, qRgb(outputPixel.r, outputPixel.g, outputPixel.b));
}

return {image, sse.getMSE()};
return {image, sse.getMSE(hasAlpha)};
}

using GenerationResult = std::tuple<QByteArray, QByteArray, QImage, MSE>;
Expand Down Expand Up @@ -207,8 +208,8 @@ GenerationResult generateRawDataFramesExpectedResultAndMse(const PixelFormatRGB
std::get<1>(result) = createRawRGBData(pixelFormat, testFrames.second, bitDepth);
}

std::tie(std::get<2>(result), std::get<3>(result)) =
generateExpectedImageAndMse(testFrames, amplificationFactor, markDifference);
std::tie(std::get<2>(result), std::get<3>(result)) = generateExpectedImageAndMse(
testFrames, amplificationFactor, markDifference, pixelFormat.hasAlpha());

return result;
}
Expand Down
Loading