策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。本文只是简单的提及,想了解比较详细,请看:
http://www.cnblogs.com/zhenyulu/articles/82017.html
C++最大的优势是什么,就是面向对象,我们可以把属性和方法都封装到一个类里面。这样我们很容易变换一种方法或者可以更容易的创建复杂的程序。而且这样可以将复杂的程序封装起来,只留一个简单易用的接口。
下面我们想创建一个简单的算法,它会确定图像中有给定颜色的所有像素。算法中图像和颜色作为输入,输出为表示有给定颜色的一个二值图像。还有一个给定的幅度范围。
// get the iterators
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 each pixel
for ( ; it!= itend; ++it, ++itout) {
// process each pixel ---------------------
// compute distance from target color
if (getDistance(*it)<minDist) {
*itout= 255;
} else {
*itout= 0;
}
// end of pixel processing ---------------- }
// Computes the distance from target color.
int getDistance(const cv::Vec3b& color) const {
return abs(color[0]-target[0])+
abs(color[1]-target[1])+
abs(color[2]-target[2]);
}
首先就是创建迭代器,然后扫描每一个像素和目标像素的差值,如果小于则创建255像素,否则是0像素,这里的计算距离是去差值的绝对值之和。显然target是一个类属性。现在让我们把它封装起来:
cv::Mat ColorDetector::process(const cv::Mat &image) {
// re-allocate binary map if necessary
// same size as input image, but 1-channel
result.create(image.rows,image.cols,CV_8U);
上述循环代码
...
return result;
}
我们刚开始就创建了输出图像,如果result的大小和深度和源图像不相同,那么result就会被从新分配。核心的代码我们已经写好了,让我们写一下剩下的部分。
class ColorDetector {
private:
// minimum acceptable distance
int minDist;
// target color
cv::Vec3b target;
// image containing resulting binary map
cv::Mat result;
ColorDetector就是我们的类名,但是为了初始化我们的类,需要一个初始化构造器,设置属性的默认值:
// empty constructor
ColorDetector() : minDist(100) {
// default parameter initialization here
target[0]= target[1]= target[2]= 0;
}
这样即使在程序运行时没有初始化类,也可以合法的运行并且返回一个正确的结果,这也是一个面向对象的策略模式,也就是运行时让参数保持合法值。当然用户设定初始值也是必不可少的,我们需要提供set和get方法:
// Sets the color distance threshold.
// Threshold must be positive,
// otherwise distance threshold is set to 0.
void setColorDistanceThreshold(int distance) {
if (distance<0)
distance=0;
minDist= distance;
}
// Gets the color distance threshold
int getColorDistanceThreshold() const {
return minDist;
}
// Sets the color distance threshold.
// Threshold must be positive,
// otherwise distance threshold is set to 0.
void setColorDistanceThreshold(int distance) {
if (distance<0)
distance=0;
minDist= distance;
}
// Gets the color distance threshold
int getColorDistanceThreshold() const {
return minDist;
}
从上述代码可以看到,我们利用了面向对象的多态性,有两个setTargetColor方法。
下面就写一个main方法来使用这个类。
int main()
{
// 1. Create image processor object
ColorDetector cdetect;
// 2. Read input image
cv::Mat image= cv::imread("boldt.jpg");
if (!image.data)
return 0;
// 3. Set input parameters
cdetect.setTargetColor(130,190,230); // here blue sky
cv::namedWindow("result");
// 4. Process the image and display the result
cv::imshow("result",cdetect.process(image));
cv::waitKey();
return 0;
}
当然我们的算法很简单。在这种模式下适合处理更复杂、更多参数的问题。在计算像素值的差时,OpenCV提供了一个计算向量欧几里得范数的函数,所以也可以写成这样:
Return
static_cast<int>(
cv::norm<int,3>(cv::Vec3i(color[0]-target[0],
color[1]-target[1],
color[2]-target[2]);
另外我们也知道,OpenCV中的大部分数据结构都对基础的算术符进行了重载,所以我们还可以把距离计算写成:
return static_cast<int>(cv::norm<uchar,3>(color-target);
这个式子看起来是对的,但是他是错误的。大家知道在这个算式当中隐含了saturate_cast方法,uchar取值范围很小,容易超出范围,如果得出的是负值,那么直接被置为0,那么显然结果错了。
下面给出完整代码:
colordetector.h
#if !defined COLORDETECT
#define COLORDETECT
#include <opencv2/core/core.hpp>
using namespace cv;
class ColorDetector
{
private :
int minDist ;
Vec3b target;
Mat result;
int getDistance(const Vec3b& color) const
{
return abs(color[0]-target[0])+abs(color[1]-target[1])+abs(color[2]-target[2]);
}
public:
ColorDetector()
{
minDist = 150;
target[0]= target[1]= target[2]= 0;
}
void setColorDistanceThreshold(int distance)
{
if (distance<0)
distance = 0;
minDist = distance;
}
int getColorDistanceThreshold()
{
return minDist;
}
void setTargetColor(unsigned char red,unsigned char green,unsigned char blue)
{
target[2] = red;
target[1] = green;
target[0] = blue;
}
void setTargetColor(Vec3b color)
{
target = color;
}
const Vec3b getTargetColor()
{
return target;
}
Mat process(const Mat &image);
}; //类声明最后面有个分号!!!!!!!!!!!!!!!!!!!!!!!!
#endifcolordetector.cpp
#include "colordetector.h"
Mat ColorDetector::process(const Mat &image) {
// re-allocate binary map if necessary
// same size as input image, but 1-channel
result.create(image.rows,image.cols,CV_8U);
// get the iterators
Mat_<Vec3b>::const_iterator it= image.begin<Vec3b>();
Mat_<Vec3b>::const_iterator itend= image.end<Vec3b>();
cv::Mat_<uchar>::iterator itout= result.begin<uchar>();
// for each pixel
for ( ; it!= itend; ++it, ++itout) {
// process each pixel ---------------------
// compute distance from target color
if (getDistance(*it)<minDist) {
*itout= 255;
} else {
*itout= 0;
}
// end of pixel processing ----------------
}
return result;
}
colorDetection.cpp
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "colordetector.h"
int main()
{
// Create image processor object
ColorDetector cdetect;
// Read input image
Mat image= imread("pascal.jpg");
if (!image.data)
return 0;
// set input parameters
cdetect.setTargetColor(130,190,230); // here blue sky
// Read image, process it and display the result
namedWindow("result");
imshow("result",cdetect.process(image));
waitKey();
return 0;
}
这是处理结果,左边是原图:
本文介绍了如何使用策略模式在OpenCV中封装颜色检测算法。通过创建一个名为ColorDetector的类,该类接受图像、颜色和幅度范围作为输入,输出为包含给定颜色的二值图像。文章探讨了类的设计,包括构造器、属性设置方法以及避免数值溢出的问题。同时,还提供了一个main方法的示例,展示如何使用该类。

380

被折叠的 条评论
为什么被折叠?



