前言
最近接到一個功能需求,用相機定時抓取圖像在界面上顯示,相機抓取圖像的間隔設定在了100ms一次。當使用者修改相機的曝光時間時,需要判斷是否過曝,如果過曝了就把像素值修改為紅色。
部落客這裡遇到了一個問題,對每張圖檔進行是否過曝檢測,由于檢測算法的執行時間太長導緻了界面的卡頓,每100ms就有一張新的圖像,然而計算并修改曝光時的像素值就花費了超過100ms(在一個很垃圾的測試機子上運作),最後通過查閱資料,與大神交流部落客優化了算法,解決了這個問題,用這一章節來記錄一下。
功能預覽
這裡以映美精相機為例,圖像分辨率為1920 x 1200
方法一:使用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;
}
}
}