mirror of
https://github.com/overte-org/overte.git
synced 2025-04-30 00:23:06 +02:00
144 lines
4.5 KiB
C++
144 lines
4.5 KiB
C++
//
|
|
// ImageComparer.cpp
|
|
//
|
|
// Created by Nissim Hadar on 18 Nov 2017.
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
#include "ImageComparer.h"
|
|
#include "common.h"
|
|
|
|
#include <cmath>
|
|
|
|
// Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity
|
|
// The value is computed for the luminance component and the average value is returned
|
|
void ImageComparer::compareImages(const QImage& resultImage, const QImage& expectedImage) {
|
|
const int L = 255; // (2^number of bits per pixel) - 1
|
|
|
|
const double K1 { 0.01 };
|
|
const double K2 { 0.03 };
|
|
const double c1 = pow((K1 * L), 2);
|
|
const double c2 = pow((K2 * L), 2);
|
|
|
|
// First go over all full 8x8 blocks
|
|
// This is done in 3 loops
|
|
// 1) Read the pixels into a linear array (an optimization)
|
|
// 2) Calculate mean
|
|
// 3) Calculate variance and covariance
|
|
//
|
|
// p - pixel in expected image
|
|
// q - pixel in result image
|
|
//
|
|
const int WIN_SIZE = 8;
|
|
int x{ 0 }; // column index (start of block)
|
|
int y{ 0 }; // row index (start of block
|
|
|
|
// Pixels are processed in square blocks
|
|
double p[WIN_SIZE * WIN_SIZE];
|
|
double q[WIN_SIZE * WIN_SIZE];
|
|
|
|
_ssimResults.results.clear();
|
|
|
|
int windowCounter{ 0 };
|
|
double ssim{ 0.0 };
|
|
double worstTileValue{ 1.0 };
|
|
|
|
double min { 1.0 };
|
|
double max { -1.0 };
|
|
|
|
while (x < expectedImage.width()) {
|
|
int lastX = x + WIN_SIZE - 1;
|
|
if (lastX > expectedImage.width() - 1) {
|
|
x -= (lastX - expectedImage.width());
|
|
}
|
|
|
|
while (y < expectedImage.height()) {
|
|
int lastY = y + WIN_SIZE - 1;
|
|
if (lastY > expectedImage.height() - 1) {
|
|
y -= (lastY - expectedImage.height());
|
|
}
|
|
|
|
// Collect pixels into linear arrays
|
|
int i{ 0 };
|
|
for (int xx = 0; xx < WIN_SIZE && x + xx < expectedImage.width(); ++xx) {
|
|
for (int yy = 0; yy < WIN_SIZE && y + yy < expectedImage.height(); ++yy) {
|
|
// Get pixels
|
|
QRgb pixelP = expectedImage.pixel(QPoint(x + xx, y + yy));
|
|
QRgb pixelQ = resultImage.pixel(QPoint(x + xx, y + yy));
|
|
|
|
// Convert to luminance
|
|
p[i] = R_Y * qRed(pixelP) + G_Y * qGreen(pixelP) + B_Y * qBlue(pixelP);
|
|
q[i] = R_Y * qRed(pixelQ) + G_Y * qGreen(pixelQ) + B_Y * qBlue(pixelQ);
|
|
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// Calculate mean
|
|
double mP{ 0.0 }; // average value of expected pixel
|
|
double mQ{ 0.0 }; // average value of result pixel
|
|
for (int j = 0; j < WIN_SIZE * WIN_SIZE; ++j) {
|
|
mP += p[j];
|
|
mQ += q[j];
|
|
}
|
|
mP /= (WIN_SIZE * WIN_SIZE);
|
|
mQ /= (WIN_SIZE * WIN_SIZE);
|
|
|
|
// Calculate variance and covariance
|
|
double sigsqP{ 0.0 };
|
|
double sigsqQ{ 0.0 };
|
|
double sigPQ{ 0.0 };
|
|
for (int j = 0; j < WIN_SIZE * WIN_SIZE; ++j) {
|
|
sigsqP += pow((p[j] - mP), 2);
|
|
sigsqQ += pow((q[j] - mQ), 2);
|
|
|
|
sigPQ += (p[j] - mP) * (q[j] - mQ);
|
|
}
|
|
sigsqP /= (WIN_SIZE * WIN_SIZE);
|
|
sigsqQ /= (WIN_SIZE * WIN_SIZE);
|
|
sigPQ /= (WIN_SIZE * WIN_SIZE);
|
|
|
|
double numerator = (2.0 * mP * mQ + c1) * (2.0 * sigPQ + c2);
|
|
double denominator = (mP * mP + mQ * mQ + c1) * (sigsqP + sigsqQ + c2);
|
|
|
|
double value { numerator / denominator };
|
|
_ssimResults.results.push_back(value);
|
|
ssim += value;
|
|
|
|
if (value < min) min = value;
|
|
if (value > max) max = value;
|
|
|
|
if (value < worstTileValue) {
|
|
worstTileValue = value;
|
|
}
|
|
|
|
++windowCounter;
|
|
|
|
y += WIN_SIZE;
|
|
}
|
|
|
|
x += WIN_SIZE;
|
|
y = 0;
|
|
}
|
|
|
|
_ssimResults.width = (int)(expectedImage.width() / WIN_SIZE);
|
|
_ssimResults.height = (int)(expectedImage.height() / WIN_SIZE);
|
|
_ssimResults.min = min;
|
|
_ssimResults.max = max;
|
|
_ssimResults.ssim = ssim / windowCounter;
|
|
_ssimResults.worstTileValue = worstTileValue;
|
|
};
|
|
|
|
double ImageComparer::getSSIMValue() {
|
|
return _ssimResults.ssim;
|
|
}
|
|
|
|
double ImageComparer::getWorstTileValue() {
|
|
return _ssimResults.worstTileValue;
|
|
}
|
|
|
|
SSIMResults ImageComparer::getSSIMResults() {
|
|
return _ssimResults;
|
|
}
|