本文主要講講怎樣對Mat矩陣進行mask操作,其實也就是對Mat矩陣的濾波操作,俗稱卷積,參考文獻為opencv自帶的tutiol及其code.
開發環境:ubuntu12.04+opencv2.4.2+Qt4.8.2+QtCreator2.5.
實驗功能:
單擊Open image按鈕,手動選擇所需濾波的原圖片。
單擊Setting按鈕,彈出對話框,選擇濾波所用的模式,這里有2種模式,分別為自己實現濾波功能和采用opencv自帶的濾波函數filter2D實現。
單擊Process按鈕,實現圖片濾波過程,並將濾波結果顯示在圖片窗口中。
濾波完成后,圖片下方法顯示濾波所采用的模式及其花耗的時間。可以方便對2種模式的效率進行對比。
實驗說明:
這次實驗圖片的顯示與前幾篇博客中采用的方法不同,前幾次是將圖片顯示在QLabel中,這次是顯示在QTextBrowser中。當在QLabel中顯示時,直接SetPixmap將圖片內容顯示上去;而在QTextBrowser中,是加載圖片路徑名,然后直接掛載的(不需要使用opencv中的imread函數)。
opencv中的saturate_cast函數,其實就是一個類型轉換函數,將圓弧括號中的類型轉換成尖括號中的類型。
opencv中的setTo函數是將指定的元素設置為指定的值,可以使用mask矩陣掩碼。
在Qt中,如果第1個窗口類要調用第2個窗口類,且我們需要在進行第2個窗口操作時改變第1個窗口類中某些變量,這時我們不能直接改變,因為是第1個類調用第2個類,所以不能由第2個類反過來改變第1個類的值,當遇到這種情況時,我們只需要將第2個類中改變的值保存在其public中即可。然后當第1個類的某個變量需要改變時,直接用第2個類中對應的public變量賦值即可,具體可見下面給出的代碼。
在類的構造函數中建立的變量,該變量的生命周期是整個類的生命周期,所以該類中其它所有函數都可以使用該變量。
實驗結果:
打開原始圖片后:
模式設置對話框:
自己實現mask結果:
用opencv自帶filter2D實現結果:
實驗主要部分代碼及注釋(附錄有工程code下載鏈接):
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QFileDialog> #include <QtGui> #include <QTextDocument> #include <iostream> using namespace std; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); mask_mode = 1; ui->textBrowser->setStyleSheet( "background-color:black" );//這種參數更簡單 ui->textBrowser->setTextColor( Qt::green ); set = new setting( this );//在構造函數中開辟的內存作用與該類的所有函數 } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_closeButton_clicked() { close(); } void MainWindow::on_openButton_clicked() { QString img_name = QFileDialog::getOpenFileName( this, "Open Image", "../mask/", tr("Image Naems( *.png *.jpeg *.jpg *.bmp )")); img = imread( img_name.toAscii().data() ); img1 = img.clone(); cvtColor( img1, img1, CV_BGR2RGB ); QImage qimg = QImage( (const unsigned char*)img1.data, img1.cols, img1.rows, QImage::Format_RGB888 ); //這是在textBrowser里顯示圖片的另一種方法。<img src='***'>這些都是固定的. //如果是string后要接arg,則不能直接""后面接,可以采用tr或QString括起來。 // ui->textBrowser->append( tr("<img src='%1'>").arg(img_name ); ui->textBrowser->clear(); ui->textBrowser->append( tr("<img src='%1'>").arg( img_name ) ); ui->textBrowser->append( tr("the mask mode is realize by myself......") ); } int MainWindow::on_settingButton_clicked() { // set = new setting( this );//如果在這個地方進行new的話,則不能保存上次設置的結果,因此應該在構造函數中new set->show(); } void MainWindow::on_processButton_clicked() { mask_mode = set->set_mask_mode; img1 = img.clone(); Mat img2; img2.create( img1.size(), img1.type() ); CV_Assert( img1.depth() == CV_8U ); if( 1 == mask_mode ) { double t = getTickCount(); int rows = img1.rows; int cols = img1.cols; int channels = img1.channels(); for( int i = 1; i < rows-1; i++ ) { uchar *current = img1.ptr<uchar>( i ); uchar *previous = img1.ptr<uchar>( i-1 ); uchar *next = img1.ptr<uchar>( i+1 ); uchar *output = img2.ptr<uchar>( i ); for( int j = channels; j < channels*(cols-1); j++ ) { *output++ = saturate_cast<uchar>( 5*current[j]-current[j-channels]-current[j+channels] -previous[j]-next[j]); } } img2.row(0).setTo(Scalar(0)); img2.row(rows-1).setTo(Scalar(0)); img2.col(0).setTo(Scalar(0)); img2.col(cols-1).setTo(Scalar(0)); t = (getTickCount()-t)/getTickFrequency()*1000; imwrite( "lena1.jpg", img2 ); ui->textBrowser->clear(); ui->textBrowser->append(tr("<img src=./lena1.jpg>")); ui->textBrowser->append( tr("the mask mode is realize by myself......") ); ui->textBrowser->append( tr("the time running cost %1ms").arg(t) ); } else if( 2 == mask_mode ) { double t = getTickCount(); Mat kernel = (Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0); filter2D( img1, img2, -1, kernel ); t = (getTickCount()-t)/getTickFrequency()*1000; imwrite( "lena2.jpg", img2 ); ui->textBrowser->clear(); ui->textBrowser->append(tr("<img src=./lena2.jpg>")); ui->textBrowser->append( tr("the mask mode is filter2D of the opencv......") ); ui->textBrowser->append( tr("the time running cost %1ms").arg(t) ); } }
setting.cpp:
#include "setting.h" #include "ui_setting.h" setting::setting(QWidget *parent) : QDialog(parent), ui(new Ui::setting) { ui->setupUi(this); set_mask_mode = 1; } setting::~setting() { delete ui; } void setting::on_closeButton_clicked() { close(); ui->~setting(); } void setting::on_realizeButton_clicked() { if( ui->realizeButton->isChecked() ) { set_mask_mode = 1; } } void setting::on_filter2dButton_clicked() { if( ui->filter2dButton->isChecked() ) { set_mask_mode = 2; } }
實驗總結:
通過本次實驗可以看到,雖然上面2種模式都實現了濾波功能,不過opencv自帶的filter2D對lena這張圖片才用3ms,而自己實現的函數用了7.5ms,差不多慢了1倍。由此可見,opencv中很多函數是進行了優化的。