OPENCV學習筆記3-4_使用模型-視圖-控制器設計應用程序
阿新 • • 發佈:2017-09-23
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(uimainwindow.cpp->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); }
#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_Hmainwindow.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); }; #endifcolordetector.h
OPENCV學習筆記3-4_使用模型-視圖-控制器設計應用程序