主要内容:
在算法设计中使用策略模式;
用控制器设计模式实现功能模块间通信;
转换颜色表示法;
用色调、饱和度、亮度表示颜色
在算法设计中使用策略模式:
策略设计模式的目的就是把算法封装进类。封装后,算法之间互相替换,或者把几个算法组合起来进行更复杂的处理,都会更加容易而且这种模式能够尽可能地将算法的复杂性隐藏在一个直观的编程接口之后,因而有利于算法的部署。
准备工作;
假设我们要构建一个简单的算法,用来识别图像中具有某种颜色的所有像素。这个算法必须输入一个图像和一个颜色,并且返回一个二值图像,显示具有指定颜色的像素。在运行算法前还要指定一个参数,即我们能接受的颜色的公差。
如何实现:
一旦用策略设计模式把算法封装进类,就可以通过创建类的实例来部署算法,实例通常是在程序初始化的时候创建的。在运行构造函数时,类的实例会用默认值初始化算法的各种参数,以便它能立即进入可用状态。我们还可以用适当的方法来读写算法的参数值。在GUI程序中,可以用多种部件(文本框、滑动条等)显示和修改参数,用户操作起来很容易。下一节将展示一个策略类的结构。这里先看一个部署和使用它的例子。我们写一个简单的主函数,调用颜色检测算法:
int main()
{
// 1. **创建图像处理器对象**
ColorDetector cdetect;
// 2. **读取输入的图像**
cv::Mat image= cv::imread("boldt.jpg");
if (image.empty())
return 0;
// 3. **设置输入参数**
cdetect.setTargetColor(230,190,130); // 这里表示蓝天
cv::namedWindow("result");
// 4. **处理图像并显示结果**
cv::imshow("result",cdetect.process(image));
cv::waitKey();return 0;
}
运行这个程序,检测第2章用过的彩色城堡图中的蓝天,输出结果如下页图所示。这里白色像素表示检测到指定的颜色,黑色表示没有检测到。很明显,封装进这个类的算法相对简单(下面我们会看到,它只是组合了一个扫描循环和一个公差参数)。当算法的实现过程更加复杂,步骤繁多,并且包含多个参数时,策略设计模式会真正显示出强大的功能。
可运行源码:
#include <iostream>
#include "opencv/cv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
//识别颜色
class ColorDetector
{
private:
int maxDist;
cv::Vec3b target;
cv::Mat result;
public:
ColorDetector() :maxDist(100), target(0, 0, 0) {}
~ColorDetector() {}
void setColorDistanceThreshold(int distance);
int getColorDistanceThreshod() const;
void setTargetColor(uchar blue, uchar green, uchar red);
void setTargetColor(cv::Vec3b color);
cv::Vec3b getTargetColor() const;
cv::Mat preocess(const cv::Mat& image);
int getDistanceToTargetColor(const cv::Vec3b& color) const;
int getColorDistance(const cv::Vec3b& color1,const cv::Vec3b& color2) const;
};
void ColorDetector::setColorDistanceThreshold(int distance)
{
if (distance < 0) distance = 0;
maxDist = distance;
}
int ColorDetector::getColorDistanceThreshod() const
{
return maxDist;
}
void ColorDetector::setTargetColor(uchar blue, uchar green, uchar red)
{
target = cv::Vec3b(blue, green, red);
}
void ColorDetector::setTargetColor(cv::Vec3b color)
{
target = color;
}
cv::Vec3b ColorDetector::getTargetColor() const
{
return target;
}
cv::Mat ColorDetector::preocess(const cv::Mat& image)
{
cv::Mat result;
result.create(image.size(), 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 (getDistanceToTargetColor(*it) <= maxDist)
{
*itout = 255;
}
else
{
*itout = 0;
}
}
return result;
}
int ColorDetector::getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const
{
return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);
}
int ColorDetector::getDistanceToTargetColor(const cv::Vec3b& color)const
{
return getColorDistance(color, target);
}
int main()
{
ColorDetector cdetect;
cv::Mat image = cv::imread("/home/joe/图片/boldt.jpg");
if (image.empty())
return 0;
cv::imshow("before", image);
cdetect.setTargetColor(20, 20, 20);//检测图像中比较黑的部分
cv::imshow("after", cdetect.preocess(image));
cv::waitKey();
return 0;
}
#这是对CMake工具最低版本要求,这里我们要检查下我们的CMake工具的版本信息,我们可以使用命令“cmake --version”查看
cmake_minimum_required(VERSION 2.6)
project(test)#这是建立一个工程项目,括号里面时工程名,工程名我们可以任意给,最后程序编译出来的可执行文件就是这个名字
FIND_PACKAGE(OpenCV REQUIRED )#用Cmake查找opencv包
set(CMAKE_CXX_STANDARD 11)#用C++11标准库编译
set(SOURCE_FILES main.cpp)
add_executable(test ${SOURCE_FILES})#这里括号里面的两个参数分别是工程项目名和我们要编译文件名的意思,记住中间一空格键隔开
TARGET_LINK_LIBRARIES(test ${OpenCV_LIBS})#这是我们链接到OpenCV库的环节,我们只要更改前面第一个参数位我们的工程项目名即可