此节介绍的架构模式(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
时间: 2024-10-01 19:42:33