OpenCV 学习笔记(3) Processing images with classes

In this chapter, we will cover:

  • City block distance and Euclidean distance(街区距离和欧式距离)
  • Using the Singleton design pattern(单例模式)
  • Converting color spaces(颜色空间转换)

  这一大章主要将如何用类来更好的封装我们写的算法,这个我觉得跟OpenCV的关系倒是不是太大,得看你C++学的6不6,项目开发经验6不6,做得多,有人提点一下,设计出来的自然会好很多。


City block distance and Euclidean distance

点A(x1, y1),点B(x2, y2),则

  • 街区距离(City block distance):
    \begin{equation}
    d=\left|x_2-x_1\right|+\left|y_2-y_1\right| \tag{1}
    \end{equation}
  • 欧式距离(Euclidean distance )
    \begin{equation}
    d=\sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} \tag{2}
    \end{equation}
      上面的距离OpenCV提供了函数可以直接用,见Norm.
      后面有时间专门整理一个关于各种距离的学习笔记(曼哈顿距离(Manhattan Distance),汉明距离(Hamming distance),马氏距离(Mahalanobis distance) etc.)

  这里还得提一下一个易错的点,如果不看,可能以后查bug都不一定都能查出来。

1
2
return static_cast<int>(
cv::norm<int,3>(cv::Vec3i(color[0]-target[0], color[1]-target[1], color[2]-target[2])));

  上面这种写法没问题,但是下面这种写法就有问题了

1
2
return static_cast<int>(
cv::norm<uchar,3>(color-target);

  按照书上说的,这些操作符,具体指的哪个呢?书上没说,我的理解是(),这个操作符会调用saturate_cast函数,这时候因为前面的模板函数里写的类型是uchar,那么如果出现负值,saturate_cast就会将其自动变成0,而不是我们期待的负数。所以将uchar改成int即可.
  
  不过现在好像已经不能这么写了,如果这样写,会直接报错,我的环境是VS2013+OpenCV2.4.9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cv::Vec3b color(100, 100, 100);
cv::Vec3b target(103, 101, 101);
int a = static_cast<int>(
cv::norm<int, 3>(cv::Vec3i(color[0] - target[0],
color[1] - target[1],
color[2] - target[2])));
printf("a=%d", a);

//这样写会报错,但是如果将color的类型变为cv::Vec3i,那么下面那句会报错,也就是说color的类型要和norm里填写的类型一致才行
int b = static_cast<int>(cv::norm<int, 3>(color - target));
printf("b=%d", b);

int c = static_cast<int>(cv::norm<uchar, 3>(color - target));
printf("c=%d", c);

Using the Singleton design pattern

  这个单例模式我今年不少找工作的同学被问到了。但是这不是OpenCV里面的知识,而是设计模式里面的,所以这里只简单的介绍一下实现方法。

单例模式的实现

  代码来自这里。静态成员实例的懒汉模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Singleton
{
private:
static Singleton* m_instance;
Singleton(){}
public:
static Singleton* getInstance();
void process();
};

Singleton* Singleton::getInstance()
{
if(NULL == m_instance)
{
Lock();//借用其它类来实现,如boost,保证线程安全
if(NULL == m_instance)
{
m_instance = new Singleton;
}
UnLock();
}
return m_instance;
}

  保证了只有一个实例,那么如何用呢?举例如下:(具体的还是得看专业的书籍)

1
Singleton::getInstance()->process();

Converting color spaces

  我们在做图像处理的时候,经常是把图片从RGB颜色空间转到其他颜色空间下处理,为什么呢?

  书中给出这样一段话,我觉得可以解释一部分原因:使用RGB颜色空间来计算颜色之间的距离并不是衡量颜色相似度最好的方法。事实上,RGB并不是一个感知上分布均匀的色彩空间(perceptually uniform color space)。这意味着在相同的距离下,两个颜色可能看起来非常相似,而另外两个颜色却截然不同。
  为了解决这个问题,人们提出了在感知上均匀分布的色彩空间。CIEL*A*B就是这样一个空间。转到一个空间下,图像像素和目标像素值之间的欧拉距离在描述颜色的相似性上才有意义。
  颜色空间转换的OpenCV函数如下,举例说明:

1
cv::cvtColor(color, gray, CV_BGR2Gray);