This commit is contained in:
NissimHadar 2019-02-28 11:43:16 -08:00
parent 72f198fe00
commit 15989e3a89
8 changed files with 87 additions and 10 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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();

View file

@ -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);

View file

@ -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");
} }

View file

@ -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;

View file

@ -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