144 lines · 4.5 KB · C++
RawDownload
////  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 returnedvoid 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;}