OpenCV2计算机编程手册(二)基于类的图像处理
2017-01-11 15:15
561 查看
1. 在算法设计中使用策略(Strategy)模式
策略设计模式的目标是将算法封装在类中。因此,可以更容易地替换一个现有的算法,或者组合使用多个算法以拥有更复杂的处理逻辑。此外,该模式将算法的复杂度隐藏在易用的编程接口背后,降低了算法的部署难度。准备工作
比方说,我们需要构建一个简单的算法,它可以鉴别出图像中含有给定颜色的所有像素。该算法输入的是图像以及颜色,并返回表示含有指定颜色的像素的二值图像,该算法还需要指定另外一个参数,即对颜色偏差的容忍度。实现方法
让我们写一个主函数,然后看看我们颜色检测算法的运行结果是什么样的:int main() { //1. 创建图像处理对象 ColorDector cdetect; //2. 读取输入图像 cv::Mat image = cv::imread("boldt.jpg"); cv::namedWindow("original", 0); cv::imshow("original", image); //3. 设置输入参数 cv::Mat result; cdetect.setTargetColor(130, 190, 230);//蓝天的颜色 //处理并显示结果 cv::namedWindow("result", 0); cv::imshow("result", cdetect.process(image, result)); cv::waitKey(0); return 0; }
#include<iostream> #include "opencv2/opencv.hpp" using namespace std; class ColorDetector{ private: //最小可接受距离 int minDist; //目标色 cv::Vec3b target; //结果图像 cv::Mat result; public: //构造函数 ColorDetector() : minDist(100) { //初始化默认参数 target[0] = target[1] = target[2] = 0; } //设置彩色距离阈值,阈值须为非负数 void setColorDistabceThreshold(int distance) { if (distance < 0) distance = 0; minDist = distance; } //获取彩色距离阈值 int getColorDistanceThreshold() const { return minDist; } //设置需检测的颜色 void setTargetColor(unsigned char red, unsigned char green, unsigned char blue) { target[2] = red; target[1] = green; target[0] = blue; } //设置需检测的颜色 void setTargetColor(cv::Vec3b color) { target = color; } //获取需检测的颜色 cv::Vec3b getTargetColor() const { return target; } //二值化处理函数 cv::Mat_<uchar> process(cv::Mat &image) { 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>(); while (it != itend) { if (getDistance(*it) < minDist) { *itout = 255; } else { *itout = 0; } it++;//更新输入迭代器 itout++;;//更新输出迭代器 } return result; } //计算颜色距离 int getDistance(const cv::Vec3b &color) const { cv::Vec3b dist; cv::absdiff(color, target, dist); return cv::sum(dist)[0]; } }; class ColorDetectController { private: ColorDetector* cdetect;//算法类 cv::Mat image;//待处理的图像 cv::Mat result;//结果 public: ColorDetectController() { cdetect = new ColorDetector(); } //设置色彩距离阈值 void setColorDistanceThreshold(int distance) { cdetect->setColorDistabceThreshold(distance); } //获取色彩距离阈值 int getColorDistancethreshold() const { return cdetect->getColorDistanceThreshold(); } //设置要检测的颜色 void setTargetColor(unsigned char red, unsigned char green, unsigned char blue) { cdetect->setTargetColor(red, green, blue); } //获取要检测的颜色 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]; } //设置输入图像,通过文件读取 bool setInputImage(string filename) { image = cv::imread(filename); if (!image.data) return false; else return true; } //返回当前的输入图像 const cv::Mat getInputImage() const { return image; } //开始处理图像 void process() { result = cdetect->process(image); } //获取最近一次处理的结果 const cv::Mat getLastResult() const { return result; } //删除当前控制器创建的处理对象 ~ColorDetectController() { delete cdetect; } };
View Code
MFC中两个按键触发函数
CFileDialog dlg(TRUE, _T("*.bmp"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, _T("image file(*.bmp;*,jpg)|*.bmp;*.jpg|ALL Files(*.*)|*.*||"), NULL); dlg.m_ofn.lpstrTitle = _T("Open Image"); // if a filename has been selected if (dlg.DoModal() == IDOK) { // get the path of the selected filename CString strMfc = dlg.GetPathName(); std::string filename = CT2CA(strMfc.GetBuffer(0)); // set and display the input image controller.setInputImage(filename); cv::imshow("Input Image", controller.getInputImage()); }
// target color is hard-coded here controller.setTargetColor(130, 190, 230); // process the input image and display result controller.process(); cv::imshow("Output Result", controller.getLastResult());
3. 使用单件(Singleton)设计模式
单件是另外一种流行的设计模式,用于简化对一个类实例的访问,同时保证在程序执行期间只有一个实例存在。准备工作
我们使用上面的 ColorDetectController 类。该类将被修改,以包含一个单件类。实现方法
要做的第一件事是添加一个私有静态成员变量,他将保存对单个类实例的引用。同时,为了禁止创建额外的类实例,构造函数也是私有的:class ColorDetectController{ private: cv::Mat image;//待处理的图像 cv::Mat result;//结果 //单件指针 static ColorDetectController *singleton; ColorDetector *cdetect; //私有构造函数 ColorDetectController() { //初始化工作 cdetect = new ColorDetector(); } ... }
此外,你还可以使复制构造函数和操作符 = 私有化,以确保无法创建独一无二的单件实例的拷贝。当一个用户的类要求单件类的一个实例时,它才被创建。这通过使用一个公有静态方法实现,如果实例不存在那么创建它,然后返回一个指向该实例的指针:
static ColorDetectController * getInstance() { if (singleton == 0) singleton = new ColorDetectController(); return singleton; }
需要注意的是,单件的实现并不是线程安全的。因此,在多线程情况下不应该使用它。
最后,因为单件实例是被动态创建,当不需要时用户必须删除它。这也是通过一个静态方法实现的:
static void destroy() { if (singleton != 0) delete singleton; singleton = 0; }
由于单件是一个静态成员变量,它必须在 .cpp 文件中定义,如下:
ColorDetectController *ColorDetectController::singleton = 0;
作用原理
因为单件可以通过一个公共的静态方法获取,所有包括单件类声明的类都能访问它。这尤其适用于控制器对象,它被多个拥有复杂GUI的窗口控件类访问。其中的任何一个GUI类都不需要声明一个成员变量,这和前一节不同。对话框类的两个回调方法编写如下:void CMy3_3单件设计模式Dlg::OnBnClickedOpen() { // TODO: 在此添加控件通知处理程序代码 CFileDialog dlg(TRUE, _T("*.bmp"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, _T("image file(*.bmp;*,jpg)|*.bmp;*.jpg|ALL Files(*.*)|*.*||"), NULL); dlg.m_ofn.lpstrTitle = _T("Open Image"); if (dlg.DoModal() == IDOK) { // get the path of the selected filename CString strMfc = dlg.GetPathName(); std::string filename = CT2CA(strMfc.GetBuffer(0)); // set and display the input image ColorDetectController::getInstance()->setInputImage(filename); cv::imshow("Input Image", ColorDetectController::getInstance()->getInputImage()); } } void CMy3_3单件设计模式Dlg::OnBnClickedProcess() { // TODO: 在此添加控件通知处理程序代码 ColorDetectController::getInstance()->setTargetColor(130, 190, 230); ColorDetectController::getInstance()->process(); cv::imshow("Output result", ColorDetectController::getInstance()->getLastResult()); }
当应用程序关闭时,单件的实例必须被释放:
void CMy3_3单件设计模式Dlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 ColorDetectController::getInstance()->destroy(); CDialog::OnOK(); }
如上所示,当一个控制器被封装在一个单件中,它变得更容易访问。然而,一个更好的实现需要一个更复杂的GUI。这将在下一节中实现。
4. 使用模型-试图-控制器(Model-View-Controller)架构设计应用程序
5. 颜色空间转换
下面先介绍几个不同的颜色空间:RGB: 基于红、绿、蓝三原色的使用。
Lab: 在感知上均匀分布的色彩空间。
HSV: 代表色调,饱和度和值(Value)。
HLS: 代表色调(Hue),饱和度(Saturation)和亮度(Lightness)。
调用方式为:
cvtColor(image_, gray, COLOR_BGR2GRAY); cvtColor(image_, hls, COLOR_BGR2HLS); cvtColor(image_, hsv, COLOR_BGR2HSV); cvtColor(image_, hsv, COLOR_BGR2Lab);
作用原理
当图像从一个颜色空间转换到另一个,线性或非线性变换将作用于每个输入像素,以产生输出像素。
注意,三原色红、绿、蓝在RGB次序或BGR次序转换到相同颜色空间是不一样的(灰度一样),比如转到HSV空间,H会相反。
#include <iostream> #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" using namespace std; using namespace cv; void Show_Image(Mat & input, char* name) { namedWindow(name, 0); imshow(name, input); } int main() { Mat image = imread("waves.jpg"); Mat hsv; cvtColor(image, hsv, COLOR_BGR2HSV); Mat channel[3]; split(hsv, channel); for (int index = 0; index < 3; index++) { char* buff[3] = { "H", "S", "V" }; Show_Image(channel[index], buff[index]); } waitKey(0); return 0; }
相关文章推荐
- 神经网络编程入门
- 计算机图形学(三)_图元的属性_16_ 反走样_7_区域边界的反走样
- 学通C#网络编程——第四篇 TCP应用编程
- 第3章运算方法和运算部件
- Android中HttpURLConnection使用详解
- State Estimation for Robotics_简介
- HttpClient4.5.2由Client客户端上传File文件流至Server服务端
- C#网络编程——第三篇 HTTP应用编程(下)
- 以resnet作为前置网络的ssd目标提取检测
- C#网络编程——第三篇 HTTP应用编程(下)
- 20170110L05-03老男孩linux实战运维培训-nfs网络文件系统服务介绍与实战01
- C#网络编程——第二篇 HTTP应用编程(上)
- Http上传下载输入输出流总结
- C#网络编程——第一篇 基础之进程线程
- HTTPS
- 采用队列数据结构按层次遍历二叉树
- 深度堆栈网络训练Python代码
- 通常每个套接字地址(协议/网络地址/端口)只允许使用一次 apache24安装443端口占用
- http://www.cnblogs.com/solverpeng/p/5830931.html
- 深度学习基础