OpenCV2学习笔记(六)

最后更新于:2022-04-01 06:35:58

##检测图像颜色小程序 设计一个界面,用来检测一幅图像的颜色分布,开发平台为Qt5.3.2+OpenCV2.4.9。 该程序的主要步骤如下:  1\. 载入图像,选定一种颜色;  2\. 设定阈值,在该值范围内判定像素属于预设的颜色;  3\. 在界面的Label中输出结果。 首先,新建一个Qt Widgets Application,其中基类选择为QWidget,在创建完项目后,添加一个检测图像颜色的类ColorDetector。并在在Qt项目的.pro文件中添加: ~~~ INCLUDEPATH+=C:\OpenCV\install\include\opencv\ C:\OpenCV\install\include\opencv2\ C:\OpenCV\install\include LIBS+=C:\OpenCV\lib\libopencv_calib3d249.dll.a\ C:\OpenCV\lib\libopencv_contrib249.dll.a\ C:\OpenCV\lib\libopencv_core249.dll.a\ C:\OpenCV\lib\libopencv_features2d249.dll.a\ C:\OpenCV\lib\libopencv_flann249.dll.a\ C:\OpenCV\lib\libopencv_gpu249.dll.a\ C:\OpenCV\lib\libopencv_highgui249.dll.a\ C:\OpenCV\lib\libopencv_imgproc249.dll.a\ C:\OpenCV\lib\libopencv_legacy249.dll.a\ C:\OpenCV\lib\libopencv_ml249.dll.a\ C:\OpenCV\lib\libopencv_nonfree249.dll.a\ C:\OpenCV\lib\libopencv_objdetect249.dll.a\ C:\OpenCV\lib\libopencv_ocl249.dll.a\ C:\OpenCV\lib\libopencv_video249.dll.a\ C:\OpenCV\lib\libopencv_photo249.dll.a\ C:\OpenCV\lib\libopencv_stitching249.dll.a\ C:\OpenCV\lib\libopencv_superres249.dll.a\ C:\OpenCV\lib\libopencv_ts249.a\ C:\OpenCV\lib\libopencv_videostab249.dll.a ~~~ 进入图形界面文件widget.ui,在其中拖入三个按键,改名为”Open Image”,”Process”,”Color”,他们分别执行载入图像、颜色检测、颜色设定的操作。同时,拖入一个Vertical Slider,用于调整颜色的阈值。最后在下方设置一个Label,图像输出在该区域中。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_5683a752e91db.jpg) 设置各个按钮的objectName,分别为:  “Open Image”设定为”openImage”  “Color”设定为”colorButton”  “Process”设定为”ImageProcess”  “Vertical Slider”设定为”verticalSlider”  这是为了在程序中将信号与槽函数相对应: ~~~ Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui -> setupUi(this); connect(ui -> openImage, SIGNAL(clicked()), this, SLOT(openImage())); connect(ui -> ImageProcess, SIGNAL(clicked()), this, SLOT(ImageProcess())); connect(ui -> colorButton, SIGNAL(clicked()), this, SLOT(colorSelect())); connect(ui -> verticalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeDis(int))); } ~~~ 这里规定当未有输入图像时,图像处理按钮不可用,在以上的Widget构造函数中添加: ~~~ // 在未输入图像时,屏蔽图像处理的按钮 ui -> ImageProcess -> setEnabled(false); ui -> colorButton -> setEnabled(false); ui -> verticalSlider -> setEnabled(false); ~~~ 接着,定义处理图像所用的类,首先是colordetector.h: ~~~ #ifndef COLORDETECTOR_H_ #define COLORDETECTOR_H_ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <string> class ColorDetector { private: int minDist; cv::Vec3b target; cv::Mat result; cv::Mat image; ColorDetector(); // 提供静态的接口来获得ColorDetector对象 static ColorDetector *singleton; public: cv::Mat getInputImage() const; // 载入图像 cv::Mat getResult() const; // 返回图像处理结果 void process(); // 将阈值范围内的像素点置为255,其余为0 int getDistance(const cv::Vec3b&) const; bool setInputImage(std::string); // 判断是否已输入图像 static ColorDetector * getInstance(); // 使用单例模式创建类的实例 static void destory(); // 一个对象的析构函数 // 设置颜色阈值 void setColorDistanceThreshold(int); int getColorDistanceThreshold() const; // 设置颜色 void setTargetColor(unsigned char, unsigned char, unsigned char); // 颜色通道转换 void setTargetColor(cv::Vec3b); cv::Vec3b getTargetColor() const; }; #endif /* COLORDETECTOR_H_ */ ~~~ 接着在colordetector.cpp中添加各函数的定义: ~~~ #include "ColorDetector.h" ColorDetector* ColorDetector::singleton = 0; ColorDetector::ColorDetector():minDist(100) { target[0] = target[1] = target[2] = 0; } ColorDetector* ColorDetector::getInstance() { if(singleton == 0) { singleton = new ColorDetector; } return singleton; } void ColorDetector::destory() { if(singleton!=0) { delete singleton; } singleton = 0; } void ColorDetector::setColorDistanceThreshold(int distance) { if(distance < 0) { distance = 0; } minDist = distance; } int ColorDetector::getColorDistanceThreshold() const { return minDist; } void ColorDetector::setTargetColor(unsigned char red, unsigned char green, unsigned char blue) { // 颜色通道转换 target[2] = red; target[1] = green; target[0] = blue; } void ColorDetector::setTargetColor(cv::Vec3b color) { target = color; } cv::Vec3b ColorDetector::getTargetColor() const { return target; } int ColorDetector::getDistance(const cv::Vec3b& color) const { return abs(color[0]-target[0])+abs(color[1]-target[1])+abs(color[2]-target[2]); } void ColorDetector::process() { result.create(image.rows, image.cols, CV_8U); cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>(); cv::Mat_<uchar>::iterator itout = result.begin<uchar>(); for(; it!=itend; ++it, ++itout) { if(getDistance(*it) < minDist) { *itout = 255; }else { *itout = 0; } } } cv::Mat ColorDetector::getResult() const { return result; } bool ColorDetector::setInputImage(std::string filename) { image = cv::imread(filename); if(!image.data) { return false; } return true; } cv::Mat ColorDetector::getInputImage() const { return image; } ~~~ 接下来定义图形界面的处理函数,首先在widget.h中添加: ~~~ #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QFileDialog> #include <QImage> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include "colordetector.h" namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; QImage qimage; cv::Mat image; private slots: void openImage(); void ImageProcess(); void colorSelect(); void changeDis(int); }; #endif // WIDGET_H ~~~ 接着在widget.cpp中定义信号与槽函数及相关操作: ~~~ #include "widget.h" #include "ui_widget.h" #include <QColorDialog> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui -> setupUi(this); // 关联信号与槽函数 connect(ui -> openImage, SIGNAL(clicked()), this, SLOT(openImage())); connect(ui -> ImageProcess, SIGNAL(clicked()), this, SLOT(ImageProcess())); connect(ui -> colorButton, SIGNAL(clicked()), this, SLOT(colorSelect())); connect(ui -> verticalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeDistance(int))); // 在未输入图像时,屏蔽图像处理的按钮 ui -> ImageProcess -> setEnabled(false); ui -> colorButton -> setEnabled(false); ui -> verticalSlider -> setEnabled(false); } Widget::~Widget() { delete ui; } void Widget::openImage() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), ".", tr("Image Files (*.png *.jpg *.jpeg *.bmp)")); ColorDetector::getInstance()->setInputImage(fileName.toLatin1().data()); cv::Mat input; input = ColorDetector::getInstance()->getInputImage(); if (!input.data) { qDebug() << "No Input Image"; } else { // 当检测到输入图像,可激活图像处理按键,并显示原图像 ui->ImageProcess->setEnabled(true); ui->colorButton->setEnabled(true); ui->verticalSlider->setEnabled(true); cv::namedWindow("image"); cv::imshow("image",ColorDetector::getInstance()->getInputImage()); } } void Widget::ImageProcess() { ColorDetector::getInstance()->process(); cv::cvtColor(ColorDetector::getInstance()->getResult(),image,CV_GRAY2RGB); qimage = QImage((const unsigned char*)(image.data),image.cols,image.rows,QImage::Format_RGB888); ui->label->setPixmap(QPixmap::fromImage(qimage).scaledToHeight(300)); } void Widget::colorSelect() { QColor color = QColorDialog::getColor(Qt::green,this); if(color.isValid()) { ColorDetector::getInstance()->setTargetColor( color.red(),color.green(),color.blue()); } } void Widget::changeDistance(int value) { ColorDetector::getInstance()->setColorDistanceThreshold(value); } ~~~ 效果如下,未输入图像时,图像处理、颜色选择按钮部分不可操作: 1.未输入图像时: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_5683a75304615.jpg) 2.载入图像后: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_5683a753177ba.jpg) 3.打开color按钮,可选择要检测的颜色: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_5683a75357dc5.jpg) 4.选定颜色后,拖动可调节阈值,点击Process可输出检测结果。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_5683a7536f74e.jpg)
';