直方图是一个简单的表,它给出了一幅图像或一组图像中拥有给定数值的像素数量。因此,灰度图像的直方图有256个条目(或称为容器)。0号容器给出值为0的像素数目,1号容器给出值为1的像素个数,以此类推。
直方图是图像内容的一个重要特性。如果一幅图像的区域中显示的是一种独特的纹理或是一个独特的物体,那么这个区域的直方图可以看做一个概率函数,它给出的是某个像素属于该纹理或物体的概率。这使得我们可以借助图像的直方图来检测特定的内容。
反投影直方图的方法是一种把目标概率分布映射到观测图像的简单方法。其作用是,替换一个输入图像中每一个像素值,使其变成感兴趣区域(ROI)的直方图中对应的概率值
其在opencv2的C++ API为:
cv::calcBackProject(&image, 1, //一幅图像 channels, //通道数量 histogram, //进行反投影的直方图 result, //生成的反投影图像 ranges, //每个维度的值域 255.0 //缩放因子 );
2、HSV颜色空间
HSV(Hue,Saturation,Value)是根据颜色的直观特性(色调H,饱和度S,亮度V)创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
取值范围为0.0~1.0,值越大,颜色越饱和。
取值范围为0.0(黑色)~1.0(白色)。
HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。
HSV颜色空间
hue表示颜色的相位角,取值范围是0---360;S表示颜色的饱和度;S为一比例值,范围从0到1,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率,通俗点讲,S表示的是某种颜色的“纯度”, S取值越大,表示色彩越纯,取值越小,表示色彩越灰。V表示色彩的明亮程度,范围从0到1。V等于0表示圆锥的底部定点,也就是黑色,V等于1表示圆锥的顶面,当V=1并且S=0时表示纯白色。
HSV圆锥
由于我们要进行的是通过一种算法来实现检测特定物体(尤其是人脸)的功能,所以通过这个示例的引入,来为后面介绍Mean Shift算法打下基础。
转换到HSV空间的原因:
因为肤色在颜色空间的分析相当集中,但会受到光照和人种的影响。为了减少肤色收光照强度的影响,通常将颜色空间从RBG转换到亮度和色度分离的某个颜色空间,如HSV颜色空间,然后放弃亮度分量。
采集肤色样本,把肤色样本中的每个像素从RGB空间转换到HSV空间,统计其H分量的直方图,并对该直方图进行归一化处理,就可以得到肤色在H空间的概率分布,该概率分布就是所需的跟踪模式。
具体步骤如下:
1、将观测图像中每个像素从RGB空间映射到HSV空间,按公式计算H分量大小建立起统计直方图
2、根据直方图进行反向投影运算,即,将观测图像中的每个像素值,用其H分量在已建立的统计直方图中对应的值代替
3、所得到输出图像就是观测图像的颜色概率分布图像
现在,用程序演示直方图反投影算法中使用颜色信息。
class ContentFinder { private: float hranges[2]; //H值 const float* ranges[3]; int channels[3]; //通道 float threshold; //阈值 cv::MatND histogram; //histogram:柱状图 public: ContentFinder():threshold(-1.0f) { ranges[0] = hranges;//所有通道的值相同 ranges[1] = hranges; ranges[2] = hranges; } void setThreshold(float t) //设置直方图的阈值[0,1] { threshold = t; } float getThreshold() //获取阈值 { return threshold; } void setHistogram(const cv::MatND& h) //设置参考直方图 { histogram = h; cv::normalize(histogram,histogram,1.0);//输入直方图必须是归一化后的 } cv::Mat find(const cv::Mat& image,float minValue,float maxValue,int* channels,int dim); }; cv::Mat ContentFinder::find(const cv::Mat& image,float minValue,float maxValue,int* channels,int dim) { cv::Mat result; hranges[0] = minValue; hranges[1] = maxValue; for(int i=0;i<dim;i++) { this->channels[i] = channels[i]; } cv::calcBackProject(&image, 1, //输入图片 channels, //所有通道列表 histogram, //直方图 result, //反投影的结果 ranges, //值域 255.0 //缩放因子 ); //进行阈值化以得到二值图像 if(threshold > 0.0) cv::threshold(result,result,255*threshold,255,cv::THRESH_BINARY); return result; }
假设我们现在知道物体的近似位置,概率映射可用于找到的对象的确切位置。最有可能的位置是在已知窗口区域中得到最大概率的位置。因此,如果我们从最初的位置开始,并且迭代移动,边可以找到精确的位置。这便是均值漂移算法所要完成的任务。
均值漂移算法以迭代的方式锁定概率函数的局部最大值。它主要是寻找预定义窗口中数据点的重心点,或者说加权平均值。该算法将窗口中心移动到数据点的重心处,并重复这个过程直到窗口重心收敛到一个稳定点。
从数学角度上说,Mean Shift算法利用概率密度的梯度爬升来寻找局部最优。当输入一个图像的范围,然后根据反向投影图和输入的方框进行Mean Shift迭代,它是向重心移动,即向反向投影图中概率大的地方移动,所以始终会移动到目标上,Mean Shift算法是一个变步长的梯度上升算法。
现考虑一个点集(这可以是经过直方图反投影的像素点的分布),现有一个小窗口,需要将其移至像素点最密集的区域。如下图所示:
meanshift_basics
最初的窗口表示为C1这个大的蓝色圆圈,其原始中心为"C1_o"。随着这个中心点向局部密度较大的区域移动,得到了"C1_r"的中心点。随着这个过程的迭代,最终会得到一个最大像素点分布的区域,即C2,该区域包含了最多数量的点。
总结下来,Mean Shift的基本思路是,从每个像素开始,首先估计有相似颜色的邻近像素点的密度(局部密度)的梯度,而后利用迭代算法求出局部密度的峰值(即重心点),把能够聚类到同一个峰值点的所有像素点划分成一个区域。
(1)选择跟踪窗口的大小和初始位置。在Mean Shift跟踪算法中,核窗宽(即核函数的定义域的大小,就是搜索窗口的大小)的大小起着非常重要的作用。因为它不但决定了参与Mean Shift迭代的样本数量,而且也反映了跟踪窗口的大小。通常,核窗宽由初始跟踪窗口的尺寸决定,而且在整个跟踪过程中不再发生变化。
meanshift_step1
(2)计算跟踪窗口内的质心(或重心)。在离散二维(2D)概率分布图像中,计算某窗口的质心同物理上计算某物体的质心一样,即利用窗口的零阶矩M00和(x,y)的一阶矩(M10,M01)之间的关系,计算得到窗口的质心。
公式
meanshift_step2
(3)调整跟踪窗口的中心到质心;
(4)重复第二步和第三步,直到跟踪窗口中心和质心“会聚”,即每次窗口移动的距离小于一定的阈值。
meanshift_step3
一般一个图像就是个矩阵,像素点均匀的分布在图像上,就没有点的稠密性。所以怎样来定义点的概率密度,这才是最关键的。而我们可以根据像素点的颜色相近来定义为概率密度高。
其作为人脸跟踪的应用由下图演示:
meanshift_face
Mean Shift作为一种高效的模式匹配算法,由于不需要进行全局搜索,而且搜索精度高,已经广泛地应用在各种模式识别、实时可视跟踪等领域。
缺乏必要的模型更新方法;整个跟踪过程中跟踪窗口的大小保持不变,当目标存在尺度变化的时候会导致尺度定位不准确。
Bradski根据Mean Shift算法的不足,提出了Camshift算法。CamShift算法,即Continuously Adaptive Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算,将上一帧结果作为下一帧的初始值,迭代下去。
该算法采用不变矩对目标的尺寸进行估算,实现了连续自适应地调整跟踪窗口的大小和位置,并将其应用在对连续彩色图像序列中的运动目标的快速跟踪。
简单点说,Mean Shift是针对单张图片寻找最优迭代结果,而Camshift则是针对视频序列来处理,并对该序列中的每一帧图片都调用Mean Shift来寻找最优迭代结果。正是由于Camshift针对一个视频序列进行处理,从而保证其可以不断调整窗口的大小,如此一来,当目标的大小发生变化的时候,该算法就可以自适应地调整目标区域继续跟踪。
Camshift算法首先根据跟踪目标颜色概率模型,将视频图像转化为概率分布图像(PDI),并初始化一个矩形搜索窗口,对每一帧PDI图像利用Mean Shift算法搜索目标匹配的最优区域,并根据搜索区域的不变矩估算跟踪目标的中心和大小,保存和输出当前帧搜索结果,并且用当前帧搜索结果作为下一帧图像初始化搜索窗口。如此循环,即可实现对目标的连续跟踪。Camshift算法是一种动态变化的非参数密度函数梯度估计方法。
(1)创建指定窗口的颜色概率分布图,初始化一个搜索窗口W,其大小为S
camshift_1
由上图左图的直方图可以知道,选定区域最常见的色度范围。假设新的视频帧到来时,每个像素点的色度值被检测,通过直方图给出该像素点的概率值。
(2)利用Mean Shift算法使搜索窗口“收敛";在2D概率分布图像中,计算搜索窗口的质心;调整搜索窗口的中心到计算的质心位置。重复该过程,直到“收敛”(即中心的位移小于给定的阈值)
(3)重新设置搜索窗口的大小S并计算跟踪目标的输出参数,并用新的窗口大小初始化下一帧Mean Shift的搜索窗口
camshift_2
上图表示通过Camshift算法跟踪人脸时计算一个视频帧图像中可能存在人脸的图像。黑色像素概率值最低,白色像素概率值最高,灰色像素介于二者之间。
(4)跳转到第二步进行下一帧的循环
下面是Camshift算法的人脸跟踪演示:
camshift_face
OpenCV 3.0.0-dev documentation
OpenCV 2 计算机视觉编程手册,科学出版社
基于OpenCV的人脸跟踪识别系统研究,雷静,西安电子科技大学,硕士学位论文,2010
Meanshift,聚类算法