视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
OpenCV成长之路(3):模仿PhotoShop中魔术棒工具
2020-11-27 14:49:42 责编:小采
文档
 本文的主题实际上是图像的颜色空间的转换,借助一个颜色选取程序来说明OpenCV中颜色转换函数的用法以及一些注意事项。

一、几种常见的颜色空间:

RGB颜色空间:RGB采用加法混色法,因为它是描述各种“光”通过何种比例来产生颜色。光线从暗黑开始不断叠加 产生颜色。RGB描述的是红绿蓝三色光的数值。数字图像存储方面一般都是用RGB模式,值得注意的是OpenCV里三通道的存储顺序是BGR。

HSV,HSI:这两个颜色格式都是根据人眼对颜色的区分来定义的格式,其中H(hue)表示色相,S(saturation)表示饱和度,V(value)表示明度,I(intensity)代表了亮度。

Lab空间:模型中均匀改变对应于在感知颜色中的均匀改变,所以我们可以把Lab想像为颜色空间中的一个点,相邻的点靠的越近说明两者的颜色越接近,所以Lab空间常用来度量两个颜色的相似性。

更多颜色空间的知识可以参考:http://en.wikipedia.org/wiki/Color_space

二、OpenCV中的颜色空间转换

OpenCV里通过cvtColor函数来完成图片的颜色转换,cvtColor是在opencv2/imgproc/imgproc.hpp头文件中定义的,它的C++接口如下:

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )

src:输入图像。

dst:输出图像。

code:颜色转换类型,比如:CV_BGR2Lab,CV_BGR2HSV,CV_HSV2BGR,CV_BGR2RGB。

dstCn:输出图像的通道号,如果默认为0,则表示按输入图像的通道数。

把image图像由BGR转换为Lab:cvtColor(image,image,CV_BGR2Lab)

三、简单的魔术棒程序

首先我们定义一个colorDetect类:

class colorDetect{private: int minDist; //minium acceptable distance Vec3b target;//target color; 
 Mat result; //the resultpublic:
 colorDetect(); void SetMinDistance(int dist); void SetTargetColor(uchar red,uchar green,uchar blue); void SetTargetColor(Vec3b color); //set the target color Mat process(const Mat& image); //main process};

其中的minDist是我们定义的阈值用于限定两种颜色之间的距离,相当于PhotoShop中魔术棒工具的阈值。

target是目标颜色,相当于种子颜色。result是存储处理得到的结果。

process是主要的处理程序,下面我们来看process的内容。

Mat colorDetect::process(const Mat& image)
{ Mat ImageLab=image.clone();
 result.create(image.rows,image.cols,CV_8U); 
 //将image转换为Lab格式存储在ImageLab中 
 cvtColor(image,ImageLab,CV_BGR2Lab); 
 //将目标颜色由BGR转换为Lab 
 Mat temp(1,1,CV_8UC3);
 temp.at<Vec3b>(0,0)=target;//创建了一张1*1的临时图像并用目标颜色填充 
 cvtColor(temp,temp,CV_BGR2Lab);
 target=temp.at<Vec3b>(0,0);//再从临时图像的Lab格式中取出目标颜色

 // 创建处理用的迭代器 
 Mat_<Vec3b>::iterator it=ImageLab.begin<Vec3b>(); 
 Mat_<Vec3b>::iterator itend=ImageLab.end<Vec3b>(); 
 Mat_<uchar>::iterator itout=result.begin<uchar>(); 
 while(it!=itend)
 { 
 //两个颜色值之间距离的计算 
 int dist=static_cast<int>(norm<int,3>(Vec3i((*it)[0]-target[0],
 (*it)[1]-target[1],(*it)[2]-target[2]))); 
 if(dist<minDist)
 (*itout)=255; 
 else 
 (*itout)=0;
 it++;
 itout++;
 } return result;
}

程序中有2点需要特别注意:

1,在将图像转换为Lab空间后,目标颜色也需要进行转换,做法是创建了一个临时图像。

2,判断两个颜色之间的距离运算了norm函数,它的运算是norm<typename,dim>(v)。其中v是一个dim维的向量。程序中是一个三维的适量,是两个颜色值两减后的结果。

那值得思考的是能不能把Vec3i((*it)[0]-target[0],(*it)[1]-target[1],(*it)[2]-target[2])替换为Vec3i((*it)-target)呢?答案是否的,因为(*it)-target在实际运算过程中会自动的把相减的结果进行类型。

我们对目标颜色和阈值进行这样的设置后可以得到一个示例的效果:

cdet.SetTargetColor(150,150,150);
cdet.SetMinDistance(50);

更多OpenCV成长之路(3):模仿PhotoShop中魔术棒工具相关文章请关注PHP中文网!

下载本文
显示全文
专题