Convert a QImage to grayscale

前端 未结 4 1137
攒了一身酷
攒了一身酷 2020-12-06 06:19

I have a QImage and I need to convert it to grayscale, then later paint over that with colors. I found an allGray() and isGrayScale() function to c

4条回答
  •  感动是毒
    2020-12-06 06:48

    Rather than using the slow functions QImage::pixel and QImage::setPixel, use QImage::scanline to access the data. Pixels on a scan (horizontal line ) are consecutive. Assuming you have a 32 bpp image, you can use QRgb to iterate over the scan. Finally always put the x coordinate in the inner loop. Which gives :

    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(scan + jj*depth);
            int gray = qGray(*rgbpixel);
            *rgbpixel = QColor(gray, gray, gray).rgba();
        }
    }
    

    A quick test with an 3585 x 2386 image gave

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

    Source code: testimage.h file:

    #ifndef TESTIMAGE_H
    #define TESTIMAGE_H
    
    #include 
    
    #include 
    #include 
    
    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 file:

    #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(scan + jj*depth);
                int gray = qGray(*rgbpixel);
                *rgbpixel = QColor(gray, gray, gray).rgba();
            }
        }
    
        }
    }
    
    QTEST_MAIN(TestImage)
    

    pro file:

    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = QImageTest
    TEMPLATE = app
    
    CONFIG  += qtestlib
    
    SOURCES += testimage.cpp
    
    HEADERS += testimage.h
    

    Important note:

    • You already get an important performance boost just by inverting the loops. In this test case it was ~90ms.
    • You may use other libraries like opencv to make the grayscale conversion and then build the Qimage from an opencv buffer. I expect an even better performance improvement.

提交回复
热议问题