Сравнение двух QImages неверно

Я работаю над приложением, которое измеряет FPS в определенной области. Проблема в том, что если в зоне ничего не происходит, я хочу, чтобы значение fps было равно 0. Но когда я начинаю измерение и, например, перемещаю окно близко к тому месту, где происходит измерение, значение fps меняется. Как будто площадь, которую я измеряю, больше, чем мне на самом деле нужно.

Я даже попробовал сохранить QImages, которые сравниваются, визуально разницы нет. Таким образом, сравнение двух QImage должно было вернуть ложь, но оно вернуло истину. Вот мой код:

#include "framecounter.h"

FrameCounter::FrameCounter(QWidget* parent) : QWidget(parent)
{
    // Connect the captureTimer's timeout signal to the captureScreen slot.
    connect(&m_captureTimer, &QTimer::timeout, this, &FrameCounter::captureScreen);

    m_elapsedTimer.start(); // Start the elapsed timer.
}

void FrameCounter::captureScreen()
{
#ifdef Q_OS_MAC
    // Capture the screen using Core Graphics
    CGImageRef cgImage = CGWindowListCreateImage(CGRectMake(m_x, m_y, m_size, m_size), kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault);
    QImage screenCapture = CGImageToQImage(cgImage);
    CGImageRelease(cgImage);
#else
    // Capture the screen using Qt
    QScreen* screen = QGuiApplication::primaryScreen();
    if (!screen)
        return;

    QImage screenCapture = screen->grabWindow(0, m_x, m_y, m_size, m_size).toImage();
#endif

    if (!m_previousFrame.isNull() && screenCapture != m_previousFrame)
    {
        ++m_frameCount;
    }

    m_previousFrame = screenCapture;
    calculateFps();
}

void FrameCounter::calculateFps()
{
    qint64 elapsed = m_elapsedTimer.elapsed();
    //Calculate the current FPS and update the list of FPS values every 300 milliseconds.
    if (elapsed >= 300)
    {
        m_currentFps = static_cast<double>(m_frameCount) / (static_cast<double>(elapsed) / 1000.0);
        if (m_currentFps!=0){
            m_listOfFps.append(m_currentFps);
        }

        // Reset the frame count and restart the timer.
        m_frameCount = 0;
        m_elapsedTimer.restart();
        emit newfpsvalue();
    }
}

void FrameCounter::startMeasurement(int x, int y, int size)
{
    // Define the measurement area and start timers
    m_x = x;
    m_y = y;
    m_size = size;
    // Start the capture timer to capture frames every 16 milliseconds.
    m_captureTimer.start(16);

    m_elapsedTimer.restart();
}

void FrameCounter::stopMeasurement()
{
    m_captureTimer.stop();

    // Reset FPS and clear the list of FPS values.
    m_currentFps = 0;
    m_listOfFps.clear();
}

double FrameCounter::getCurrentFps() const
{
    // Return the current FPS value.
    return m_currentFps;
}

#ifdef Q_OS_MAC
CGBitmapInfo FrameCounter::CGBitmapInfoForQImage(const QImage &image)
{
    CGBitmapInfo bitmapInfo = kCGImageAlphaNone;

    switch (image.format()) {
    case QImage::Format_ARGB32:
        bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
        break;
    case QImage::Format_RGB32:
        bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
        break;
    case QImage::Format_RGBA8888_Premultiplied:
        bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
        break;
    case QImage::Format_RGBA8888:
        bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
        break;
    case QImage::Format_RGBX8888:
        bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
        break;
    case QImage::Format_ARGB32_Premultiplied:
        bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
        break;
    default:
        break;
    }

    return bitmapInfo;
}

QImage FrameCounter::CGImageToQImage(CGImageRef cgImage)
{
    const size_t width = CGImageGetWidth(cgImage);
    const size_t height = CGImageGetHeight(cgImage);
    QImage image(static_cast<int>(width), static_cast<int>(height), QImage::Format_ARGB32_Premultiplied);
    image.fill(Qt::transparent);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
    CGContextRef context = CGBitmapContextCreate(static_cast<void*>(image.bits()), static_cast<size_t>(image.width()), static_cast<size_t>(image.height()), 8,
                                                 static_cast<size_t>(image.bytesPerLine()), colorSpace, CGBitmapInfoForQImage(image));

           // Scale the context so that painting happens in device-independent pixels
    const qreal devicePixelRatio = image.devicePixelRatio();
    CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);

    CGRect rect = CGRectMake(0, 0, width, height);
    CGContextDrawImage(context, rect, cgImage);

    CFRelease(colorSpace);
    CGContextRelease(context);

    return image;
}
#endif

Кто-нибудь знает, в чем может быть причина этого? Связано ли это с захватом или сравнением QImage?

Если это может помочь, если я измеряю область, где верхний левый угол имеет эти координаты (300 300) и размер (250 250), значение FPS меняется всякий раз, когда что-то происходит в области с верхним левым углом примерно (245 205) и размером примерно (360 375).

Обновлено: Как было предложено, я сравнил значения пикселей и увидел, что когда окно приближается к ним, некоторые значения RGB немного меняются, поэтому я реализовал функцию, которая сравнивает два QImage и допускает небольшие изменения:

bool FrameCounter::framesAreEqual(const QImage& img1, const QImage& img2) const
{
    if (img1.size() != img2.size())
        return false;

    int width  = img1.width();
    int height = img1.height();

    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            QRgb pixel1 = img1.pixel(x, y);
            QRgb pixel2 = img2.pixel(x, y);

            int redDiff   = qAbs(qRed(pixel1) - qRed(pixel2));
            int greenDiff = qAbs(qGreen(pixel1) - qGreen(pixel2));
            int blueDiff  = qAbs(qBlue(pixel1) - qBlue(pixel2));
            if (redDiff > 15 || greenDiff > 15 || blueDiff > 15)
            {
                return false;
            }
        }
    }

    return true;
}

Это работает, но я все еще не полностью удовлетворен этим решением. Кто-нибудь знает, почему значение пикселя меняется при движении рядом с областью, в которой происходит измерение?

Обновлено еще раз: Проблема была в тени окон. Когда окно приближается, его тень попадает в область измерения.

я бы зарегистрировал значения пикселей и сравнил, действительно ли оба изображения одинаковы. визуально вы не увидите никаких мелких отличий.

Marco F. 29.05.2024 11:08

Я попробовал это, и когда я перемещаю окно близко к этой области, значения некоторых пикселей меняются, но ненамного. Нужно ли мне создавать собственную функцию сравнения, допускающую небольшие изменения пикселей, или это приведет к тому, что сравнение будет неправильным, если фактическое изменение находится в этом диапазоне?

ASM 29.05.2024 11:31

Если вы хотите оценить небольшие изменения как равные, вам придется реализовать сравнение самостоятельно. В противном случае посмотрите здесь: stackoverflow.com/questions/24722699/…

Marco F. 29.05.2024 12:15

Я реализовал свою собственную функцию сравнения, которая позволяет определить определенный диапазон различий. Кажется, сейчас это работает, но я не уверен в том, как это распределено. В любом случае, спасибо.

ASM 29.05.2024 13:33

Затем @ASM рассмотрите возможность: 1. опубликовать ответ с вашим текущим решением (с соответствующим минимально воспроизводимым примером); 2. обновите свой вопрос и объясните, почему это вас не убеждает.

musicamante 30.05.2024 02:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эта проблема была вызвана, как я упоминал в EDIT 2, тенями окон, которые изменили значение пикселей. Поэтому я удалил функцию FramesAreEqual, допускающую небольшие изменения, и оставил код как есть, поскольку приложение, скорее всего, будет использоваться в полноэкранных окнах.

Другие вопросы по теме