传统的编程思路都是面向过程的,C++则是面向对象的编程,那么我们设计程序时应该充分使用C++封装的思想,把图像处理抽象成类。这样便于代码的维护和移植。
本篇的例子是构建一个简单算法,鉴别出图像中含有给定颜色的所有像素。该算法输入的是图像及颜色,并返回表示含有指定颜色的像素的二值图像。该算法还需要指定另一个参数,即对颜色偏差的容忍度。
但由于RGB颜色空间计算颜色之间的距离并不是衡量颜色相似度最好的方法,事实上,RGB并不是一个感知上均匀分布的色彩空间。为了解决这个问题,人们提出了感知上均匀分布的色彩空间,CIEL*a*b就是这样一个颜色空间。opencv函数cv::cvtColor可以轻易的在不同颜色空间进行转换。
下面贴代码:
ColorDetector.h
#pragma
once
#include
#include
class
ColorDetector
{
private
:
cv::
Mat
m_converted;
//转换颜色空间的图片
int
m_threshod;
//容忍度偏差
cv::
Vec3b
m_model;
//要查找的颜色
public
:
cv::
Mat
m_result;
//最终得到的二值图像
ColorDetector();
~ColorDetector();
void
setModel(cv::
Vec3b
&
target
);
//设置要查找的颜色
void
setModel(
uchar
red
,
uchar
green
,
uchar
blue
);
//设置查找颜色的接口,这种颜色值设置在RGB通道上
void
setModel2(
uchar
red
,
uchar
green
,
uchar
blue
);
//设置查找颜色的接口,这种颜色值转换到LAB颜色空间上
void
setThreshold(
int
distance
);
//设置容忍度的接口
int
getDistance(cv::
Vec3b
&
pixls
);
//解算图像像素点与要查找的颜色的距离
cv::
Mat
process(
const
cv::
Mat
&
image
);
cv::
Mat
process2(
const
cv::
Mat
&
image
);
};
ColorDetector.cpp
#include
"ColorDetector.h"
//构造函数,给成员变量初始化,容忍度偏差设为100,查找的三通道颜色默认设为0
ColorDetector
::ColorDetector():m_threshod(100)
{
m_model
[
0
]
= m_model
[
1
]
= m_model
[
2
]
= 0;
}
ColorDetector
::~ColorDetector()
{
}
void
ColorDetector
::setModel(cv::
Vec3b
&
target
)
{
m_model
=
target
;
//cv::Vec3b类型,三通道
}
void
ColorDetector
::setModel(
uchar
red
,
uchar
green
,
uchar
blue
)
{
m_model
[
0
]
=
blue
;
m_model
[
1
]
=
green
;
m_model
[
2
]
=
red
;
}
void
ColorDetector
::setModel2(
uchar
red
,
uchar
green
,
uchar
blue
)
{
cv::
Mat
tmp(1, 1,
CV_8UC3
);
//定义一个三通道的像素点
tmp.at
Vec3b
>(0, 0)
[
0
]
=
blue
;
tmp.at
Vec3b
>(0, 0)
[
1
]
=
green
;
tmp.at
Vec3b
>(0, 0)
[
2
]
=
red
;
cv::cvtColor(tmp, tmp,
CV_BGR2Lab
);
//颜色空间转换,把RGB——>Lab
m_model
=
tmp.at
Vec3b
>(0, 0);
}
void
ColorDetector
::setThreshold(
int
distance
)
{
m_threshod =
distance
;
//设置容忍度
}
//这里的距离公式采用1范数
int
ColorDetector
::getDistance(cv::
Vec3b
&
pixls
)
{
return
abs(
pixls
[
0
]
- m_model
[
0
]
)
+ abs(
pixls
[
1
]
- m_model
[
1
]
)
+ abs(
pixls
[
2
]
- m_model
[
2
]
);
}
cv::
Mat
ColorDetector
::process(
const
cv::
Mat
&
image
)
{
m_result.create(
image
.size
()
,
CV_8U
);
cv::
Mat_
Vec3b
>::
const_iterator
it =
image
.begin
Vec3b
>();
cv::
Mat_
Vec3b
>::
const_iterator
itend =
image
.end
Vec3b
>();
cv::
Mat_
<
uchar
>::
iterator
out = m_result.begin<
uchar
>();
while
(it
!=
itend)
{
//循环遍历,把查找到的颜色转换为二值图像,这里按照RGB空间的颜色距离解算
if
(getDistance(
*
it) < m_threshod)
*
out = 255;
else
*
out = 0;
++
it;
++
out;
}
return
m_result;
}
cv::
Mat
ColorDetector
::process2(
const
cv::
Mat
&
image
)
{
m_result.create(
image
.size
()
,
CV_8U
);
m_converted.create(
image
.size
()
,
image
.type());
//把输入图像从RGB颜色空间转换到Lab颜色空间
cv::cvtColor(
image
, m_converted,
CV_BGR2Lab
);
cv::
Mat_
Vec3b
>::
const_iterator
it = m_converted.begin
Vec3b
>();
cv::
Mat_
Vec3b
>::
const_iterator
itend = m_converted.end
Vec3b
>();
cv::
Mat_
<
uchar
>::
iterator
out = m_result.begin<
uchar
>();
while
(it
!=
itend)
{
if
(getDistance(
*
it) < m_threshod)
*
out = 255;
else
*
out = 0;
++
it;
++
out;
}
return
m_result;
}
main.cpp
#include
"ColorDetector.h"
int
main()
{
cv::
Mat
image = cv::imread(
"boldt.jpg"
);
ColorDetector
detector;
//构造类
detector.setModel(130, 190, 230);
//查找蓝天的颜色
cv::namedWindow(
"Process"
);
cv::imshow(
"Process"
, detector.process(image));
detector.setModel2(130, 190, 230);
//查找蓝天的颜色
cv::namedWindow(
"Process2"
);
cv::imshow(
"Process2"
, detector.process2(image));
cv::waitKey(0);
return
0;
}
运行结果:
参考原图: