• 基础学习笔记之opencv(10):Mat mask操作


      本文主要讲讲怎样对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自带的filter2Dlena这张图片才用3ms,而自己实现的函数用了7.5ms,差不多慢了1倍。由此可见,opencv中很多函数是进行了优化的。

     

      附:工程code下载。

     

     

     

     

    作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:tornadomeet,欢迎交流!)
  • 相关阅读:
    JavaEmail的使用之邮件发送
    《将博客搬至CSDN》
    利用myqr库创建自己的二维码
    魔幻离现实仅一步之遥:细说Python的循环调用、循环引用和循环导入
    Locust做接口性能测试测时候RemoteDisconnected的解决办法(ConnectionError(ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))))
    python定时简单爬取网页新闻存入数据库并发送邮件
    利用Python爬取京东商品的一种办法
    基于visual c++之windows核心编程代码分析(42)windows下进程的身份切换
    基于visual c++之windows核心编程代码分析(44)监测任意程序函数起始地址
    基于visual c++之windows核心编程代码分析(46)遍历数字证书
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2605417.html
Copyright © 2020-2023  润新知