传统的编程思路都是面向过程的,C++则是面向对象的编程,那么我们设计程序时应该充分使用C++封装的思想,把图像处理抽象成类。这样便于代码的维护和移植。
本篇的例子是构建一个简单算法,鉴别出图像中含有给定颜色的所有像素。该算法输入的是图像及颜色,并返回表示含有指定颜色的像素的二值图像。该算法还需要指定另一个参数,即对颜色偏差的容忍度。
但由于RGB颜色空间计算颜色之间的距离并不是衡量颜色相似度最好的方法,事实上,RGB并不是一个感知上均匀分布的色彩空间。为了解决这个问题,人们提出了感知上均匀分布的色彩空间,CIEL*a*b就是这样一个颜色空间。opencv函数cv::cvtColor可以轻易的在不同颜色空间进行转换。
下面贴代码:
ColorDetector.h
#pragma
once
#include<opencv2\opencv.hpp>
#include<iostream>
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<cv::Vec3b>(0,
0)[0]
=
blue;
tmp.at<cv::Vec3b>(0,
0)[1]
=
green;
tmp.at<cv::Vec3b>(0,
0)[2]
=
red;
cv::cvtColor(tmp, tmp,
CV_BGR2Lab);//颜色空间转换,把RGB——>Lab
m_model
=
tmp.at<cv::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_<cv::Vec3b>::const_iterator
it =
image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator
itend =
image.end<cv::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_<cv::Vec3b>::const_iterator
it = m_converted.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator
itend = m_converted.end<cv::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;
}
#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;
}
运行结果:参考原图: