OpenCV2学习笔记(六):检测图像颜色小程序

设计一个界面,用来检测一幅图像的颜色分布,开发平台为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,图像输出在该区域中。

OpenCV2学习笔记(六):检测图像颜色小程序_第1张图片

设置各个按钮的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.未输入图像时:

OpenCV2学习笔记(六):检测图像颜色小程序_第2张图片

2.载入图像后:

OpenCV2学习笔记(六):检测图像颜色小程序_第3张图片

3.打开color按钮,可选择要检测的颜色:

OpenCV2学习笔记(六):检测图像颜色小程序_第4张图片

4.选定颜色后,拖动可调节阈值,点击Process可输出检测结果。

OpenCV2学习笔记(六):检测图像颜色小程序_第5张图片

你可能感兴趣的:(C++,qt,opencv,图像处理,阈值分割)