1. 程式人生 > >OPENCV學習筆記3-4_使用模型-視圖-控制器設計應用程序

OPENCV學習筆記3-4_使用模型-視圖-控制器設計應用程序

main hold sse model getters core tpi sso data

  此節介紹的架構模式(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_使用模型-視圖-控制器設計應用程序