Invece di utilizzare il slow functionsQImage::pixel
e QImage::setPixel
, utilizzare QImage::scanline
per accedere ai dati. I pixel su una scansione (linea orizzontale) sono consecutivi. Supponendo che tu abbia un'immagine a 32 bpp, puoi usare QRgb per iterare sulla scansione. Infine metti sempre la coordinata x nel loop interno. Il che dà:
for (int ii = 0; ii < image.height(); ii++) {
uchar* scan = image.scanLine(ii);
int depth =4;
for (int jj = 0; jj < image.width(); jj++) {
QRgb* rgbpixel = reinterpret_cast<QRgb*>(scan + jj*depth);
int gray = qGray(*rgbpixel);
*rgbpixel = QColor(gray, gray, gray).rgba();
}
}
Un test rapido con un'immagine 3585 x 2386 diede
********* Start testing of TestImage *********
Config: Using QTest library 4.7.4, Qt 4.7.4
PASS : TestImage::initTestCase()
RESULT : TestImage::grayscaleOp():
390 msecs per iteration (total: 390, iterations: 1)
PASS : TestImage::grayscaleOp()
RESULT : TestImage::grayscaleFast():
125 msecs per iteration (total: 125, iterations: 1)
PASS : TestImage::grayscaleFast()
PASS : TestImage::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped
********* Finished testing of TestImage *********
Codice sorgente: file di testimage.h:
#ifndef TESTIMAGE_H
#define TESTIMAGE_H
#include <QtTest/QtTest>
#include <QObject>
#include <QImage>
class TestImage : public QObject
{
Q_OBJECT
public:
explicit TestImage(QObject *parent = 0);
signals:
private slots:
void grayscaleOp();
void grayscaleFast();
private:
QImage imgop;
QImage imgfast;
};
#endif // TESTIMAGE_H
file di testimage.cpp:
#include "testimage.h"
TestImage::TestImage(QObject *parent)
: QObject(parent)
, imgop("path_to_test_image.png")
, imgfast("path_to_test_image.png")
{
}
void TestImage::grayscaleOp()
{
QBENCHMARK
{
QImage& image = imgop;
for (int ii = 0; ii < image.width(); ii++) {
for (int jj = 0; jj < image.height(); jj++) {
int gray = qGray(image.pixel(ii, jj));
image.setPixel(ii, jj, QColor(gray, gray, gray).rgb());
}
}
}
}
void TestImage::grayscaleFast()
{
QBENCHMARK {
QImage& image = imgfast;
for (int ii = 0; ii < image.height(); ii++) {
uchar* scan = image.scanLine(ii);
int depth =4;
for (int jj = 0; jj < image.width(); jj++) {
QRgb* rgbpixel = reinterpret_cast<QRgb*>(scan + jj*depth);
int gray = qGray(*rgbpixel);
*rgbpixel = QColor(gray, gray, gray).rgba();
}
}
}
}
QTEST_MAIN(TestImage)
pro lima:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QImageTest
TEMPLATE = app
CONFIG += qtestlib
SOURCES += testimage.cpp
HEADERS += testimage.h
Nota importante:
- È già ottenere un importante incremento delle prestazioni semplicemente invertendo i cicli. In questo caso di test era
~90ms
.
- È possibile utilizzare altre librerie come opencv per effettuare la conversione in scala di grigi e quindi creare Qimage da un buffer opencv. Mi aspetto un miglioramento delle prestazioni ancora migliore.
Anche se questo non sarà ancora il modo migliore, provare a passare il vostro per i loop (in modo da eseguire iterazioni ii prima, jj secondo). A seconda del layout della memoria, ciò potrebbe migliorare la coerenza della cache e rendere il codice più veloce. – Daerst
@Daerst Sì, buon suggerimento, ma inutile ottimizzare una soluzione se trovo comunque una soluzione migliore. Se non esiste altra soluzione, allora forse. – sashoalm