mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 19:56:44 +02:00
WIP.
This commit is contained in:
parent
72f198fe00
commit
15989e3a89
8 changed files with 87 additions and 10 deletions
|
@ -12,9 +12,17 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
ImageComparer::ImageComparer() {
|
||||||
|
_ssimResults = new SSIMResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageComparer::~ImageComparer() {
|
||||||
|
delete _ssimResults;
|
||||||
|
}
|
||||||
|
|
||||||
// Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity
|
// Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity
|
||||||
// The value is computed for the luminance component and the average value is returned
|
// The value is computed for the luminance component and the average value is returned
|
||||||
double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const {
|
double ImageComparer::compareImages(const QImage& resultImage, const QImage& expectedImage) const {
|
||||||
const int L = 255; // (2^number of bits per pixel) - 1
|
const int L = 255; // (2^number of bits per pixel) - 1
|
||||||
|
|
||||||
const double K1 { 0.01 };
|
const double K1 { 0.01 };
|
||||||
|
@ -96,6 +104,7 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
|
||||||
double numerator = (2.0 * mP * mQ + c1) * (2.0 * sigPQ + c2);
|
double numerator = (2.0 * mP * mQ + c1) * (2.0 * sigPQ + c2);
|
||||||
double denominator = (mP * mP + mQ * mQ + c1) * (sigsqP + sigsqQ + c2);
|
double denominator = (mP * mP + mQ * mQ + c1) * (sigsqP + sigsqQ + c2);
|
||||||
|
|
||||||
|
_ssimResults->results.push_back(numerator / denominator);
|
||||||
ssim += numerator / denominator;
|
ssim += numerator / denominator;
|
||||||
++windowCounter;
|
++windowCounter;
|
||||||
|
|
||||||
|
@ -106,5 +115,12 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
|
||||||
y = 0;
|
y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ssimResults->width = (int)(expectedImage.width() / WIN_SIZE);
|
||||||
|
_ssimResults->height = (int)(expectedImage.height() / WIN_SIZE);
|
||||||
|
|
||||||
return ssim / windowCounter;
|
return ssim / windowCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SSIMResults* ImageComparer::getSSIMResults() {
|
||||||
|
return _ssimResults;
|
||||||
|
}
|
||||||
|
|
|
@ -10,12 +10,21 @@
|
||||||
#ifndef hifi_ImageComparer_h
|
#ifndef hifi_ImageComparer_h
|
||||||
#define hifi_ImageComparer_h
|
#define hifi_ImageComparer_h
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
class ImageComparer {
|
class ImageComparer {
|
||||||
public:
|
public:
|
||||||
double compareImages(QImage resultImage, QImage expectedImage) const;
|
ImageComparer();
|
||||||
|
~ImageComparer();
|
||||||
|
|
||||||
|
double compareImages(const QImage& resultImage, const QImage& expectedImage) const;
|
||||||
|
SSIMResults* getSSIMResults();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SSIMResults* _ssimResults;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ImageComparer_h
|
#endif // hifi_ImageComparer_h
|
||||||
|
|
|
@ -99,3 +99,35 @@ void MismatchWindow::on_abortTestsButton_clicked() {
|
||||||
QPixmap MismatchWindow::getComparisonImage() {
|
QPixmap MismatchWindow::getComparisonImage() {
|
||||||
return _diffPixmap;
|
return _diffPixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPixmap MismatchWindow::getSSIMResultsImage(SSIMResults* ssimResults) {
|
||||||
|
// This is an optimization, as QImage.setPixel() is embarrassingly slow
|
||||||
|
const int ELEMENT_SIZE { 8 };
|
||||||
|
unsigned char* buffer = new unsigned char[(ssimResults->height * ELEMENT_SIZE) * (ssimResults->width * ELEMENT_SIZE ) * 3];
|
||||||
|
|
||||||
|
|
||||||
|
// loop over each SSIM result (a double in [-1.0 .. 1.0]
|
||||||
|
int i { 0 };
|
||||||
|
for (int y = 0; y < ssimResults->height; ++y) {
|
||||||
|
for (int x = 0; x < ssimResults->width; ++x) {
|
||||||
|
////QRgb pixelP = expectedImage.pixel(QPoint(x, y));
|
||||||
|
|
||||||
|
////// Convert to luminance
|
||||||
|
////double p = R_Y * qRed(pixelP) + G_Y * qGreen(pixelP) + B_Y * qBlue(pixelP);
|
||||||
|
|
||||||
|
////// The intensity value is modified to increase the brightness of the displayed image
|
||||||
|
////double absoluteDifference = fabs(p - q) / 255.0;
|
||||||
|
////double modifiedDifference = sqrt(absoluteDifference);
|
||||||
|
|
||||||
|
////int difference = (int)(modifiedDifference * 255.0);
|
||||||
|
|
||||||
|
////buffer[3 * (x + y * expectedImage.width()) + 0] = difference;
|
||||||
|
////buffer[3 * (x + y * expectedImage.width()) + 1] = difference;
|
||||||
|
////buffer[3 * (x + y * expectedImage.width()) + 2] = difference;
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QPixmap();
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ public:
|
||||||
UserResponse getUserResponse() { return _userResponse; }
|
UserResponse getUserResponse() { return _userResponse; }
|
||||||
|
|
||||||
QPixmap computeDiffPixmap(QImage expectedImage, QImage resultImage);
|
QPixmap computeDiffPixmap(QImage expectedImage, QImage resultImage);
|
||||||
|
|
||||||
QPixmap getComparisonImage();
|
QPixmap getComparisonImage();
|
||||||
|
QPixmap getSSIMResultsImage(SSIMResults* ssimResults);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_passTestButton_clicked();
|
void on_passTestButton_clicked();
|
||||||
|
|
|
@ -40,7 +40,7 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) {
|
||||||
|
|
||||||
_ui.plainTextEdit->setReadOnly(true);
|
_ui.plainTextEdit->setReadOnly(true);
|
||||||
|
|
||||||
setWindowTitle("Nitpick - v3.0.0");
|
setWindowTitle("Nitpick - v3.0.1");
|
||||||
|
|
||||||
clientProfiles << "VR-High" << "Desktop-High" << "Desktop-Low" << "Mobile-Touch" << "VR-Standalone";
|
clientProfiles << "VR-High" << "Desktop-High" << "Desktop-Low" << "Mobile-Touch" << "VR-Standalone";
|
||||||
_ui.clientProfileComboBox->insertItems(0, clientProfiles);
|
_ui.clientProfileComboBox->insertItems(0, clientProfiles);
|
||||||
|
|
|
@ -100,12 +100,14 @@ int Test::compareImageLists() {
|
||||||
};
|
};
|
||||||
|
|
||||||
_mismatchWindow.setTestResult(testResult);
|
_mismatchWindow.setTestResult(testResult);
|
||||||
|
|
||||||
|
QPixmap ssimResultsPixMap = _mismatchWindow.getSSIMResultsImage(_imageComparer.getSSIMResults());
|
||||||
|
|
||||||
if (similarityIndex < THRESHOLD) {
|
if (similarityIndex < THRESHOLD) {
|
||||||
++numberOfFailures;
|
++numberOfFailures;
|
||||||
|
|
||||||
if (!isInteractiveMode) {
|
if (!isInteractiveMode) {
|
||||||
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), true);
|
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), ssimResultsPixMap, true);
|
||||||
} else {
|
} else {
|
||||||
_mismatchWindow.exec();
|
_mismatchWindow.exec();
|
||||||
|
|
||||||
|
@ -113,7 +115,7 @@ int Test::compareImageLists() {
|
||||||
case USER_RESPONSE_PASS:
|
case USER_RESPONSE_PASS:
|
||||||
break;
|
break;
|
||||||
case USE_RESPONSE_FAIL:
|
case USE_RESPONSE_FAIL:
|
||||||
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), true);
|
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), ssimResultsPixMap, true);
|
||||||
break;
|
break;
|
||||||
case USER_RESPONSE_ABORT:
|
case USER_RESPONSE_ABORT:
|
||||||
keepOn = false;
|
keepOn = false;
|
||||||
|
@ -124,7 +126,7 @@ int Test::compareImageLists() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), false);
|
appendTestResultsToFile(testResult, _mismatchWindow.getComparisonImage(), ssimResultsPixMap, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_progressBar->setValue(i);
|
_progressBar->setValue(i);
|
||||||
|
@ -156,7 +158,7 @@ int Test::checkTextResults() {
|
||||||
return testsFailed.length();
|
return testsFailed.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Test::appendTestResultsToFile(TestResult testResult, QPixmap comparisonImage, bool hasFailed) {
|
void Test::appendTestResultsToFile(const TestResult& testResult, const QPixmap& comparisonImage, const QPixmap& ssimResultsImage, bool hasFailed) {
|
||||||
// Critical error if Test Results folder does not exist
|
// Critical error if Test Results folder does not exist
|
||||||
if (!QDir().exists(_testResultsFolderPath)) {
|
if (!QDir().exists(_testResultsFolderPath)) {
|
||||||
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + _testResultsFolderPath + " not found");
|
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + _testResultsFolderPath + " not found");
|
||||||
|
@ -216,6 +218,14 @@ void Test::appendTestResultsToFile(TestResult testResult, QPixmap comparisonImag
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the SSIM results image
|
||||||
|
sourceFile = testResult._pathname + testResult._actualImageFilename;
|
||||||
|
destinationFile = resultFolderPath + "/" + "SSIM results.png";
|
||||||
|
if (!QFile::copy(sourceFile, destinationFile)) {
|
||||||
|
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
comparisonImage.save(resultFolderPath + "/" + "Difference Image.png");
|
comparisonImage.save(resultFolderPath + "/" + "Difference Image.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ public:
|
||||||
|
|
||||||
void includeTest(QTextStream& textStream, const QString& testPathname);
|
void includeTest(QTextStream& textStream, const QString& testPathname);
|
||||||
|
|
||||||
void appendTestResultsToFile(TestResult testResult, QPixmap comparisonImage, bool hasFailed);
|
void appendTestResultsToFile(const TestResult& testResult, const QPixmap& comparisonImage, const QPixmap& ssimResultsImage, bool hasFailed);
|
||||||
void appendTestResultsToFile(QString testResultFilename, bool hasFailed);
|
void appendTestResultsToFile(QString testResultFilename, bool hasFailed);
|
||||||
|
|
||||||
bool createTestResultsFolderPath(const QString& directory);
|
bool createTestResultsFolderPath(const QString& directory);
|
||||||
|
@ -116,7 +116,7 @@ private:
|
||||||
const QString TEST_RESULTS_FOLDER { "TestResults" };
|
const QString TEST_RESULTS_FOLDER { "TestResults" };
|
||||||
const QString TEST_RESULTS_FILENAME { "TestResults.txt" };
|
const QString TEST_RESULTS_FILENAME { "TestResults.txt" };
|
||||||
|
|
||||||
const double THRESHOLD{ 0.935 };
|
const double THRESHOLD{ 0.98 };
|
||||||
|
|
||||||
QDir _imageDirectory;
|
QDir _imageDirectory;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef hifi_common_h
|
#ifndef hifi_common_h
|
||||||
#define hifi_common_h
|
#define hifi_common_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
|
||||||
class TestResult {
|
class TestResult {
|
||||||
|
@ -39,4 +40,11 @@ const double R_Y = 0.212655f;
|
||||||
const double G_Y = 0.715158f;
|
const double G_Y = 0.715158f;
|
||||||
const double B_Y = 0.072187f;
|
const double B_Y = 0.072187f;
|
||||||
|
|
||||||
|
class SSIMResults {
|
||||||
|
public:
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
std::vector<double> results;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_common_h
|
#endif // hifi_common_h
|
Loading…
Reference in a new issue