初学OpenCV学习记录(四)

以下内容摘自OpnCV2 计算机视觉编程手册

引言

图像是由像素组成的,像素值在图像中的分布情况是这幅图像的一个重要特征,因此可以使用直方图对像素值进行统计。
直方图就是一个表,它给出一幅图像或一组图像拥有给定值的像素的数目。
例如:在一个单通道的灰度图像中,灰度值的值介于0-255之间,我们统计该图像的直方图就可以由256个容器,0号容器表示灰度值为0的像素的数目,1号容器表示灰度值为1的像素的数目,依次类推。

前置内容

彩色图像有RGB三个通道,每个通道的强度值都是一个8位的uchar值,范围为0-255,那么一个像素的颜色组合就有256256256中,大于1600万个,为了降低分析的复杂度,需要降低颜色的数目。
比如:将每个维度的颜色数降低为原来的1/8,那么总的颜色数就是323232,即像素值为0-7的都变为4,像素值8-15的都变为12,依次类推
将每个维度的颜色数降低为原来的1/n,处理每个像素的代码如下:

data[i]=data[i]/n*n+n/2;

直方图的用途

获取直方图并不难,我们只要指定图像、通道、范围、最大最小像素值等参数,调用cv::calcHist函数即可得到,而直方图只是代表统计信息,如何利用直方图实现我们的图像处理算法才是重点,在该书的第4章中给出了直方图的几种用法,这里进行一个简单的总结和概括。

(1)直方图均衡化

如果我们对一些图片计算直方图,就会发现有些图片它的像素值仅仅分布在某一个范围内,或者可能是某些颜色值出现的频率过高,这两种情况都会使得图像的质量变差,事实上,我们认为一副高质量的图像应该是平均使用所有的像素强度。
以灰度图为例,在一个完全均衡的直方图中,每一个容器由同等数量的像素,比如我的一张图片由25600个像素,那么每个容器就都应该有100个像素。
对一幅普通的图片,我们可以使用equalize()函数将其均衡化,当然直方图无法完全均衡。
equalize()函数的原理就是使用了查找表将原图的像素值进行了重映射:
查找表实际上就是一个简单的一对一或者多对一的函数,定义了如何将像素值转化为新的像素值,本质上是一个一维数组。
使用查找表的过程为:

  • 针对灰度图创建一个查找表:cv::Mat lookup(1,256,CV_8U);
  • 建立映射关系:新的灰度值=lookup[旧的灰度值] 例如:lookup.at< uchar >(i)=255-i这种映射关系表示原图中像素值为i的像素的值要变为255-i
  • 使用cv::LUT()函数利用查找表生成新的图像

我们可以使用查找表技术去修改图像的像素值。

(2)利用反投影直方图检测特定的图像内容

如果有一张图片,希望检测出图片中的特定的内容,可能是一个物体,就可以使用这种方法。
主要过程如下:

  • 选择感兴趣区域,区域中包含目标物体的一份样板,比如说图片中有很多个苹果,可以先选择其中一个苹果所在区域作为感兴趣区域。
  • 提取感兴趣区域的直方图,并将直方图归一化,使用到的归一化函数为cv::normalize(),得到的直方图就代表了目标物体的像素特征,直方图归一化后,每个容器内的值就是像素数目与总数目的比值,我们可以把归一化后的直方图看做一个概率函数,它给出了某个像素属于该物体的概率。
  • 使用cv::calcBackProject()函数得到输出图像,函数就是把原图片中每一个像素值替换成了概率值,这个概率值就是根据上一步的归一化的直方图转换得到的。
  • 使用cv::threshold()函数对输出图像二值化,二值化图像可以清楚的看到哪里可能是该物体。

使用这种方法最好是用带颜色信息的RGB图像,当然颜色信息要进行缩减,其他步骤需要调用的函数都不变,只不过RGB图像需要对3个通道统计直方图,因此,相关的函数参数需要改变。

(3)利用反投影直方图和均值漂移算法查找物体

假设我们已经知道第一张照片中物体的近似位置,那么我们可以从最初的位置开始,迭代移动,找到第二张照片中找到物体的所在位置。
主要过程如下:

  • 在第一张照片中使用(2)所示的方法获得物体近似位置处的直方图,近似位置使用cv::Rect表示
  • 利用上一步得到的直方图和(2)所示的方法输出第二张照片的反投影(二值化图像)
  • 创建一个cv::TermCriteria 对象,该对象中设置了迭代的最大次数和窗口中心位移值,最后,使用cv::meanShift函数利用均值漂移算法找到目标物体所在的新位置,算法的原理就是找到预定义窗口(第一步中的近似位置)中反投影输出图的数据重心,然后将窗口中心移动到数据重心处,然后再重复这个过程,直到窗口重心收敛到一个稳定的点处。

(4) 通过比较直方图检索相似图片

通过比较两张图片的直方图来获得两张图片的相似性

  • 计算两个图片的直方图
  • 使用cv::compareHist()函数比较两个图像的相似度,函数会返回一个分数表明相似度

比较方法有很多种,可以通过函数的参数指定,这里不再赘述。

猜你喜欢

转载自blog.csdn.net/weixin_42411702/article/details/123845356