Anstatt mit dem slow functionsQImage::pixel
und QImage::setPixel
verwenden QImage::scanline
auf die Daten zugreifen. Pixel auf einem Scan (horizontale Linie) sind aufeinanderfolgend. Angenommen, Sie haben ein 32 bpp-Bild, können Sie QRgb verwenden, um über den Scan zu iterieren. Schließlich lege immer die x-Koordinate in die innere Schleife. Welche gibt:
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();
}
}
Ein schneller Test mit einem Bild 3585 x 2386 gab
********* 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 *********
Quellcode: testimage.h Datei:
#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
testimage.cpp Datei:
#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 Datei:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QImageTest
TEMPLATE = app
CONFIG += qtestlib
SOURCES += testimage.cpp
HEADERS += testimage.h
Wichtiger Hinweis:
- Sie bereits eine wichtige Leistungssteigerung nur erhalten, indem die Schlaufen zu invertieren. In diesem Testfall war es
~90ms
.
- Sie können andere Bibliotheken wie opencv verwenden, um die Graustufen-Konvertierung durchzuführen und dann Qimage aus einem opencv-Puffer zu erstellen. Ich erwarte eine noch bessere Leistungsverbesserung.
Während dies noch nicht der beste Weg sein, versuchen Sie, für Schleifen Schalten (so Sie ii iterieren zuerst, jj Sekunde). Abhängig vom Speicherlayout könnte dies zu einer besseren Cache-Kohärenz führen und den Code schneller machen. – Daerst
@Daerst Ja, guter Vorschlag, aber keine Optimierung eines Workaround, wenn ich sowieso eine bessere Lösung finde. Wenn keine andere Lösung existiert, dann vielleicht. – sashoalm