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)