天天看點

Qt中使用openCV修改圖檔局部顔色算法優化

作者:QT進階進階

前言

最近接到一個功能需求,用相機定時抓取圖像在界面上顯示,相機抓取圖像的間隔設定在了100ms一次。當使用者修改相機的曝光時間時,需要判斷是否過曝,如果過曝了就把像素值修改為紅色。

部落客這裡遇到了一個問題,對每張圖檔進行是否過曝檢測,由于檢測算法的執行時間太長導緻了界面的卡頓,每100ms就有一張新的圖像,然而計算并修改曝光時的像素值就花費了超過100ms(在一個很垃圾的測試機子上運作),最後通過查閱資料,與大神交流部落客優化了算法,解決了這個問題,用這一章節來記錄一下。

功能預覽

這裡以映美精相機為例,圖像分辨率為1920 x 1200

Qt中使用openCV修改圖檔局部顔色算法優化

方法一:使用Qt中的QImage

void GlobalFun::overExposure(QImage& image)
{
    DWORD start_time = GetTickCount();

    for ( int i = 0; i < image.width(); ++i )
    {
        for ( int j = 0; j < image.height(); ++j )
        {
            QColor color = image.pixelColor(i, j);
            if ( color.red() >= 254 && color.green() >= 254 && color.blue() >= 254 )
            {
                image.setPixelColor(i, j, QColor(255, 0, 0));
            }
        }
    }

    DWORD end_time = GetTickCount();
    std::cout << "times = " << end_time - start_time << std::endl;
}
           

使用Qt封裝好的QImage類去擷取rgb值,做出判斷并修改,此方法運作耗時最多,在測試機上運作一次需要280ms左右

方法二:使用openCV拆分通道

void GlobalFun::overExposure(QImage& image)
{
    DWORD start_time = GetTickCount();
    
    mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(),     image.bytesPerLine());

    std::vector<cv::Mat1b> rgbChannels;
    cv::split(mat, rgbChannels);
    cv::Mat1b red = rgbChannels[0];
    cv::Mat1b green = rgbChannels[1];
    cv::Mat1b blue = rgbChannels[2];

    mat.setTo(cv::Vec3b{255, 0, 0}, red >= 254 & green >= 254 & blue >= 254);

    DWORD end_time = GetTickCount();
    std::cout << "times = " << end_time - start_time << std::endl;
}
           

此方法比QImage操作有了較大的優化,耗時在90ms左右,把mat類型資料拆分成單通道資料,依次判斷并使用setTo修改rgb值

QT開發交流+赀料君羊:714620761

方法三:用指針操作圖像像素

void GlobalFun::overExposure(QImage& image)
{
    DWORD start_time = GetTickCount();
    
    unsigned char *data = image.bits();
    int width = image.width();
    int height = image.height();
    
    for ( int i = 0; i < width; ++i )
    {
        for ( int j = 0; j < height; ++j )
        {
            if ( *data >= 254 && *(data + 1) >= 254 && *(data + 2) >= 254 )
            {
                *(data + 1) = 0;
                *(data + 2) = 0;
            }
            data += 3;
        }
    }
    
    DWORD end_time = GetTickCount();
    std::cout << "times = " << end_time - start_time << std::endl;
}
           

用指針周遊圖像效率特别快,此方法僅需0-15ms,最後部落客選擇了使用指針來周遊,達到了功能需求

不同類型的圖像周遊

以上三個方法的圖像類型都是 QImage::Format_RGB888,如果是其他類型的圖像,周遊方式需要稍作改變,這裡以 QImage::Format_RGB32 為例

void GlobalFun::overExposure(QImage& image)
{
    unsigned char *data = image.bits();
    int width = image.width();
    int height = image.height();
    
    for ( int i = 0; i < width; ++i )
    {
        for ( int j = 0; j < height; ++j )
        {
            if ( *data >= 254 && *(data + 1) >= 254 && *(data + 2) >= 254 )
            {
                *data = 0;
                *(data + 1) = 0;
            }
            data += 4;
        }
    }
}
           

繼續閱讀