2015-01-14 10 views
6

में कनवर्ट करें मेरे पास एक QImage है और मुझे इसे ग्रेस्केल में परिवर्तित करने की आवश्यकता है, फिर बाद में रंगों के साथ उस पर पेंट करें। मुझे यह देखने के लिए allGray() और isGrayScale() फ़ंक्शन मिला है कि कोई छवि पहले से ही ग्रेस्केल है, लेकिन toGrayScale() या समान नामित फ़ंक्शन नहीं है।एक QImage को ग्रेस्केल

अभी मैं इस कोड का उपयोग कर रहा है, लेकिन है यह एक बहुत अच्छा प्रदर्शन नहीं है:

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()); 
    } 
} 

क्या होगा सबसे अच्छा तरीका है, प्रदर्शन के लिहाज से, एक QImage स्केल के लिए कन्वर्ट करने के लिए?

+0

हालांकि यह अभी भी नहीं सबसे अच्छा तरीका हो जाएगा, छोरों के लिए अपने स्विचिंग (ताकि आप ii पुनरावृति की कोशिश पहला, जेजे दूसरा)। मेमोरी लेआउट के आधार पर, इससे बेहतर कैश कोहिरेंसी हो सकती है और कोड को तेज़ बना दिया जा सकता है। – Daerst

+0

@ डेरस्ट हाँ, अच्छा सुझाव, लेकिन अगर मुझे कोई बेहतर समाधान मिल जाए तो कोई कामकाज अनुकूलन नहीं करेगा। यदि कोई अन्य समाधान मौजूद नहीं है, तो शायद। – sashoalm

उत्तर

8

slow functionsQImage::pixel और QImage::setPixel का उपयोग कर के बजाय, डेटा का उपयोग करने QImage::scanline का उपयोग करें। एक स्कैन (क्षैतिज रेखा) पर पिक्सल लगातार हैं। मान लें कि आपके पास 32 बीपीपी छवि है, आप स्कैन पर फिर से चलाने के लिए क्यूआरजीबी का उपयोग कर सकते हैं। अंत में हमेशा आंतरिक लूप में एक्स समन्वय डाल दें। कौन देता है: 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 

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(); 
    } 
} 

एक 3585 x 2386 छवि के साथ एक त्वरित परीक्षण

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

स्रोत कोड दिया

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) 

समर्थक फ़ाइल:

QT  += core gui 

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 

TARGET = QImageTest 
TEMPLATE = app 

CONFIG += qtestlib 

SOURCES += testimage.cpp 

HEADERS += testimage.h 

महत्वपूर्ण नोट:

  • आप पहले से ही बस छोरों inverting द्वारा एक महत्वपूर्ण प्रदर्शन बढ़ावा मिलता है। इस परीक्षण मामले में यह ~90ms था।
  • आप ग्रेस्केल रूपांतरण करने के लिए ओपनसीवी जैसे अन्य पुस्तकालयों का उपयोग कर सकते हैं और फिर ओपनसीवी बफर से क्यूमेज का निर्माण कर सकते हैं। मैं एक बेहतर प्रदर्शन सुधार की उम्मीद करता हूं।
4

मैं @ UmNyobe के कोड का थोड़ा संशोधित संस्करण पोस्ट करूंगा। मैं सिर्फ इंडेक्स के माध्यम से प्रत्येक पिक्सेल की गणना करने के बजाय स्कैन लाइनों के लिए एक पॉइंटर बढ़ाता हूं।

// We assume the format to be RGB32!!! 
Q_ASSERT(image.format() == QImage::Format_RGB32); 
for (int ii = 0; ii < image.height(); ii++) { 
    QRgb *pixel = reinterpret_cast<QRgb*>(image.scanLine(ii)); 
    QRgb *end = pixel + image.width(); 
    for (; pixel != end; pixel++) { 
     int gray = qGray(*pixel); 
     *pixel = QColor(gray, gray, gray).rgb(); 
    } 
} 
0

आंतरिक क्यूटी वर्ग QPixmapColorizeFilter समारोह grayscale कि इसी तरह के विषय को हल करती है उपयोग करता है।

मैंने उससे निम्नलिखित फ़ंक्शन प्राप्त किया, जिससे समस्या हल होनी चाहिए।

महत्वपूर्ण हिस्सा छवि को 32-बिट प्रारूप में परिवर्तित कर रहा है, इसलिए आप प्रत्येक पिक्सेल को 32-बिट मान के रूप में मान सकते हैं और आपको बिट संरेखण के बारे में चिंता करने की आवश्यकता नहीं है।

आप bits फ़ंक्शन का भी उपयोग कर सकते हैं और लाइनों और कॉलमों पर फिर से चलने के बजाय सभी पिक्सल पर फिर से उपयोग कर सकते हैं।इस चाल के साथ आप scanLine फ़ंक्शन में प्रदर्शन गुणा से बचें।

QImage convertToGrayScale(const QImage &srcImage) { 
    // Convert to 32bit pixel format 
    QImage dstImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? 
       QImage::Format_ARGB32 : QImage::Format_RGB32); 

    unsigned int *data = (unsigned int*)dstImage.bits(); 
    int pixelCount = dstImage.width() * dstImage.height(); 

    // Convert each pixel to grayscale 
    for(int i = 0; i < pixelCount; ++i) { 
     int val = qGray(*data); 
     *data = qRgba(val, val, val, qAlpha(*data)); 
     ++data; 
    } 

    return dstImage; 
    } 
+0

बिट्स काम करता है जब आप दो पंक्तियों के बीच लगातार पिक्सल की गारंटी देते हैं। मैंने अधिक रूढ़िवादी होने के लिए स्कैनलाइन का उपयोग किया। उदाहरण के लिए 'QImage :: QImage (uchar * डेटा, int चौड़ाई, int ऊंचाई, int बाइट्सलाइनलाइन, प्रारूप प्रारूप) का उपयोग करके बनाई गई एक छवि' 'बाइट्सलाइनलाइन> चौड़ाई * sizeofpixel()' हो सकती है। – UmNyobe

1

क्यूटी 5.5 के बाद से, आप QImage::convertToFormat() कॉल कर सकते हैं के रूप में इस स्केल के लिए एक QImage कन्वर्ट करने के लिए:

QImage image = ...; 
image.convertToFormat(QImage::Format_Grayscale8); 
संबंधित मुद्दे