OPENCV学习笔记3-4_使用模型-视图-控制器设计应用程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OPENCV学习笔记3-4_使用模型-视图-控制器设计应用程序相关的知识,希望对你有一定的参考价值。

  此节介绍的架构模式(MVC),将联合使用模型-视图-控制器(Model-View-Controller)三个模式以及其他的类。其清晰地分离程序中的逻辑部分与用户交互部分。此节将使用MVC模式构建一个基于QT的图形界面应用程序。

  模型包含关于应用程序的信息,它拥有所有由应用程序处理的数据。当出现新的数据,它将告知控制器,后者要求视图来显示结果。通常模型将集合多个算法,它们很有可能按照策略模式进行实现。

  视图职责之一是发送用户的命令到控制器。当新数据可用时,它会刷新自己以显示新的信息。

  控制器将视图和模型桥接在一起。接收视图的请求,并转化为模型中的合适方法。它也会在模型更改状态时,得到通知,并请求视图刷新以显示新的信息。

  本模型使用ColorDetector类,包含应用程序的逻辑和底层数据。然后实现一个控制器即ColorDetectController类。MVC架构下,用户界面只是简单地调用控制器方法,不包含任何应用数据,也没实现任何应用逻辑。因此,容易替换接口。

技术分享

技术分享
#include <QApplication>

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
main.cpp
技术分享
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //select color
    connect(ui->pushButton_color, SIGNAL(clicked()), this, SLOT(setColor()));
    connect(ui->actionChoose_Color, SIGNAL(triggered()), this, SLOT(setColor()));

    //open image
    connect(ui->pushButton_openImage, SIGNAL(clicked()), this, SLOT(setImage()));
    connect(ui->actionOpen_Image, SIGNAL(triggered()), this, SLOT(setImage()));

    //process Color Detection
    connect(ui->pushButton_process, SIGNAL(clicked()), this, SLOT(processColorDetection()));
    connect(ui->actionProcess, SIGNAL(triggered()), this, SLOT(processColorDetection()));

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void MainWindow::setImage()
{
    QFileDialog::Options options;
    QString selectedFilter;
    QString fileName = QFileDialog::getOpenFileName(this,
                                tr("Open Image Files"),
                                "",
                                tr("Image files (*.jpg *.jpeg *.png *.gif *.bmp)"),
                                &selectedFilter,
                                options);
    if (!fileName.isEmpty()){
        //在Qt的应用程序中定义的fileName是QString类型,而cout只能输出String类型
        //要将QString类型转换为String类型

        cv::Mat img_mat = cv::imread(fileName.toStdString(),1); //0 for grayscale
        displayMat(img_mat);
    }
    //Set Filename
    ColorDetectController::getInstance()->setInputImage(fileName.toStdString());
}

//Convert cv::Mat to QImage and display
void MainWindow::displayMat(const cv::Mat& image){

    //BGR openCV Mat to QImage
    QImage img_qt = QImage((const unsigned char*)image.data,image.cols, image.rows, image.step, QImage::Format_RGB888);

    //For Binary Images
    if (img_qt.isNull()){
        //ColorTable for Binary Images
        QVector<QRgb> colorTable;
        for (int i = 0; i < 256; i++)
            colorTable.push_back(qRgb(i, i, i));

        img_qt = QImage((const unsigned char*)image.data,image.cols, image.rows, QImage::Format_Indexed8);
        img_qt.setColorTable(colorTable);
        }

    //Display the QImage in the Label
    //简单地转换一下为Image对象,rgbSwapped是为了显示效果色彩好一些。
    QPixmap img_pix = QPixmap::fromImage(img_qt.rgbSwapped()); //BGR to RGB
    //  pix = pix.scaled(width*2,height*2,Qt::KeepAspectRatio);
    //  将图片的宽和高都扩大两倍,并且在给定的矩形内保持宽高的比值

    this->ui->label->setPixmap(img_pix.scaled(ui->label->size(), Qt::KeepAspectRatio));
}


void MainWindow::on_verticalSlider_Threshold_valueChanged(int value)
{
    QString cdt("Color Distance Threshold: ");
    cdt.append(QString::number(value));
    this->ui->label_2->setText(cdt);
}


void MainWindow::setColor()
{
    QColor color = QColorDialog::getColor(Qt::green, this); //打开颜色对话框时,默认是Qt::white
    if (color.isValid()) {
       ColorDetectController::getInstance()->setTargetColor(color.red(),color.green(),color.blue());
    }
}

void MainWindow::processColorDetection()
{
    ColorDetectController::getInstance()->setColorDistanceThreshold(ui->verticalSlider_Threshold->value());
    ColorDetectController::getInstance()->process();

    cv::Mat resulting = ColorDetectController::getInstance()->getLastResult();
    if (!resulting.empty())
        displayMat(resulting);

}
mainwindow.cpp
技术分享
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileDialog>
#include <QColorDialog>

//OpenCV
#include "cv.h"
#include "highgui.h"

//color detector, controller
#include "colorDetectController.h"
#include "colordetector.h"

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void changeEvent(QEvent *e);
    void displayMat(const cv::Mat& img);

    //Main Image
    //cv::Mat img_mat;

private:
    Ui::MainWindow *ui;

private slots:
    void on_pushButton_color_clicked();
    void processColorDetection();
    void on_verticalSlider_Threshold_valueChanged(int value);

    void setColor();
    void setImage();


};

#endif // MAINWINDOW_H
mainwindow.h
技术分享
#include "colorDetectController.h"

ColorDetectController *ColorDetectController::singleton=0; 
colorDetectController.cpp
技术分享
#if !defined CD_CNTRLLR
#define CD_CNTRLLR

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "colordetector.h"

class ColorDetectController {

  private:

     static ColorDetectController *singleton; // pointer to the singleton

    ColorDetector *cdetect;

    // The image to be processed
    cv::Mat image;
    cv::Mat result;
    
  public:
    ColorDetectController() { // private constructor

          //setting up the application
          cdetect= new ColorDetector();
    }

      // Sets the color distance threshold
      void setColorDistanceThreshold(int distance) {

          cdetect->setColorDistanceThreshold(distance);
      }

      // Gets the color distance threshold
      int getColorDistanceThreshold() const {

          return cdetect->getColorDistanceThreshold();
      }

      // Sets the color to be detected
      void setTargetColor(unsigned char red, unsigned char green, unsigned char blue) {

          cdetect->setTargetColor(red,green,blue);
      }

      // Gets the color to be detected
      void getTargetColor(unsigned char &red, unsigned char &green, unsigned char &blue) const {

          cv::Vec3b color= cdetect->getTargetColor();

          red= color[2];
          green= color[1];
          blue= color[0];
      }

      // Sets the input image. Reads it from file.
      bool setInputImage(std::string filename) {

          image= cv::imread(filename);

          if (!image.data)
              return false;
          else
              return true;
      }

      // Returns the current input image.
      const cv::Mat getInputImage() const {

          return image;
      }

      // Performs image processing.
      void process() {

          result= cdetect->process(image);
      }
      

      // Returns the image result from the latest processing.
      const cv::Mat getLastResult() const {

          return result;
      }

      // Deletes all processor objects created by the controller.
      ~ColorDetectController() {

          delete cdetect;
      }

      // Singleton static members
      static ColorDetectController *getInstance() {

          if (singleton == 0)
            singleton= new ColorDetectController;

          return singleton;
      }

      // Releases the singleton instance of this controller.
      static void destroy() {

          if (singleton != 0) {
              delete singleton;
              singleton= 0;
          }
      }
};
colorDetectController.h
技术分享
#include "colordetector.h"
    
cv::Mat ColorDetector::process(const cv::Mat &image) {
    
      // re-allocate binary map if necessary
      // same size as input image, but 1-channel
      result.create(image.rows,image.cols,CV_8U);

      // re-allocate intermediate image if necessary
      converted.create(image.rows,image.cols,image.type());

      // Converting to Lab color space 
      cv::cvtColor(image, converted, CV_BGR2Lab);

      // get the iterators
      cv::Mat_<cv::Vec3b>::iterator it= converted.begin<cv::Vec3b>();
      cv::Mat_<cv::Vec3b>::iterator itend= converted.end<cv::Vec3b>();
      cv::Mat_<uchar>::iterator itout= result.begin<uchar>();

      // for each pixel
      for ( ; it!= itend; ++it, ++itout) {
        
        // process each pixel ---------------------

          // compute distance from target color
          if (getDistance(*it)<minDist) {

              *itout= 255;

          } else {

              *itout= 0;
          }

        // end of pixel processing ----------------
      }

      return result;
}
colordetector.cpp
技术分享
#if !defined COLORDETECT
#define COLORDETECT


#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>


class ColorDetector {

  private:

      // minimum acceptable distance
      int minDist; 

      // target color
      cv::Vec3b target; 

      // image containing resulting binary map
      cv::Mat result;

      // image containing color converted image
      cv::Mat converted;

      // inline private member function
      // Computes the distance from target color.
      int getDistance(const cv::Vec3b& color) const {
         // return static_cast<int>(cv::norm<int,3>(cv::Vec3i(color[0]-target[0],color[1]-target[1],color[2]-target[2])));
          return abs(color[0]-target[0])+
                    abs(color[1]-target[1])+
                    abs(color[2]-target[2]);
      }

  public:

      // empty constructor
      ColorDetector() : minDist(100) { 

          // default parameter initialization here
          target[0]= target[1]= target[2]= 0;
      }

      // Getters and setters

      // Sets the color distance threshold.
      // Threshold must be positive, otherwise distance threshold
      // is set to 0.
      void setColorDistanceThreshold(int distance) {

          if (distance<0)
              distance=0;
          minDist= distance;
      }

      // Gets the color distance threshold
      int getColorDistanceThreshold() const {

          return minDist;
      }

      // Sets the color to be detected
      void setTargetColor(unsigned char red, unsigned char green, unsigned char blue) {

          cv::Mat tmp(1,1,CV_8UC3);              //创建一个一行一列有三通道像素
          tmp.at<cv::Vec3b>(0,0)[0]= blue;
          tmp.at<cv::Vec3b>(0,0)[1]= green;
          tmp.at<cv::Vec3b>(0,0)[2]= red;

            // Converting the target to Lab color space 
          cv::cvtColor(tmp, tmp, CV_BGR2Lab);    //使用/usr/local/lib/libopencv_imgproc.so

          target= tmp.at<cv::Vec3b>(0,0);
      }

      // Sets the color to be detected
      void setTargetColor(cv::Vec3b color) {

          cv::Mat tmp(1,1,CV_8UC3);
          tmp.at<cv::Vec3b>(0,0)= color;

            // Converting the target to Lab color space 
          cv::cvtColor(tmp, tmp, CV_BGR2Lab);

          target= tmp.at<cv::Vec3b>(0,0);
      }

      // Gets the color to be detected
      cv::Vec3b getTargetColor() const {

          return target;
      }

      // Processes the image. Returns a 1-channel binary image.
      cv::Mat process(const cv::Mat &image);
};


#endif
colordetector.h

 

以上是关于OPENCV学习笔记3-4_使用模型-视图-控制器设计应用程序的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV学习笔记之课后习题练习3-4

OPENCV学习笔记3-3_单件模式

OPENCV学习笔记16_用控制器设计模式实现功能模块间通信

Backbone学习笔记

AngularJS 学习笔记--01

SpringMVC学习笔记