》》点赞,收藏+关注,理财&技术不迷路《《
目录:
对像素值进行统计。因为每个像素值的像素是0-255,对每个像素值有多少个像素点进行统计的。
图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征。
上图显然 100+ 像素值的像素是最多的。14个像素点可以表示2^14种颜色。
bin的大小 = 图中不同像素值的个数(256) / bin的数目
直方图中bin的含义:计算颜色直方图需要将颜色空间划分为若干小的颜色区间,即直方图的bin,通过计算颜色在每个小区间内德像素得到颜色直方图,bin越多,直方图对颜色的分辨率越强,但增加了计算机的负担。即(上图所分10个竖条区域,每个竖条区域称为一个bin)
(2)简单来说直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中。bin中的数值就是从数据中计算出的特征的统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。无论如何,直方图获得的是数据分布的统计图。直方图实际上是一个方便表示图像特征的手段。
或者说,每个直方图,通常都可以用一个列向量来表示,列向量里面的每一个bin,比如说列向量有50个元素,那么就代表有50个bin。
8.1 py-cv显示直方图的两种方式
看图像特征一般第一反映都是先分析直方图。通过直方图来看图像特点然后来看怎么修改该图像。一定要知道直方图的波峰波谷代表什么意思。
也可以通过直方图来做图像分割。
直方图是像素的统计学上的特种,它统计的是各个像素值在像素可表达范围内出现的频次。比如在0-255范围,每个像素值出现的频次是多少,然而我们就构建了直方图或者像素折线图。
第一种方法:
plt.hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, normed=None)
x:指定要绘制直方图的数据;输入值,这需要一个数组或者一个序列,不需要长度相同的数组。
bins:指定直方图条形的个数;
range:指定直方图数据的上下界,默认包含绘图数据的最大值和最小值;
density:布尔,可选。如果"True",返回元组的第一个元素将会将计数标准化以形成一个概率密度,也就是说,直方图下的面积(或积分)总和为1。这是通过将计数除以数字的数量来实现的观察乘以箱子的宽度而不是除以总数数量的观察。如果叠加也是“真实”的,那么柱状图被规范化为1。(替代normed)
weights:该参数可为每一个数据点设置权重;
cumulative:是否需要计算累计频数或频率;
bottom:可以为直方图的每个条形添加基准线,默认为0;
histtype:指定直方图的类型,默认为bar,除此还有’barstacked’, ‘step’, ‘stepfilled’;
align:设置条形边界值的对其方式,默认为mid,除此还有’left’和’right’;
orientation:设置直方图的摆放方向,默认为垂直方向;
rwidth:设置直方图条形宽度的百分比;
log:是否需要对绘图数据进行log变换;
color:设置直方图的填充色;
label:设置直方图的标签,可通过legend展示其图例;
stacked:当有多个数据时,是否需要将直方图呈堆叠摆放,默认水平摆放;
normed:是否将直方图的频数转换成频率;(弃用,被density替代)
alpha:透明度,浮点数。
A.ravel() —— 将N维数组降维到一维
最简单直接粗暴的方式:
Python中的 enumerate() 函数:
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
语法:enumerate(sequence, [start=0])
sequence -- 一个序列、迭代器或其他支持迭代对象。
start -- 下标起始位置。
计算直方图:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist
其中第一个参数必须用方括号括起来。
第二个参数是用于计算直方图的通道,这里使用灰度图计算直方图,所以就直接使用第一个通道;
第三个参数是Mask,这里没有使用,所以用None。
第四个参数是histSize,表示这个直方图分成多少份(即多少个直方柱)。第二个例子将绘出直方图,到时候会清楚一点。
第五个参数是表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
最后是两个可选参数,由于直方图作为函数结果返回了,所以第六个hist就没有意义了(待确定)
最后一个accumulate是一个布尔值,用来表示直方图是否叠加。
彩色图像不同通道的直方图
设置坐标轴的范围可以通过axis(), xlim()和ylim()三个来设置,axis()用来同时设置x轴和y轴,后面的两个都是针对于特定的坐标轴而言。重点,中间参数要以列表形式传入!
第二种方法:
通过图像本身来显示。
8.2 直方图应用
直方图均衡化 = 调整图像对比度。
直方图均衡化都是基于 灰度图像!!equalizeHist是一种手段,帮我们自动调整图片对比度,图像增强的一个手段。
8.2.1 全局均衡化Global Histogram Equalization
cv.equalizeHist()
完全自动,没有任何参数可以调节。有考虑到局部图像区域(Local Region),自适应过程就是在均衡化的过程中只利用局部区域窗口内的直方图分布来构建映射函数 f。
先看直方图均衡化(HE)
HE是一种很常用的直方图类方法,基本思想是通过图像的灰度分布直方图确定一个变换函数,用来对图像进行灰度变换,以达到提高图像对比度的目的。该变换函数就是一个累积分布函数(CDF)
算法步骤
(1) 计算输入图像img的灰度直方图S
(2) 进行归一化处理,并计算归一化之后的累积分布密度 f(Hist)
(3) 计算灰度值映射,得到新的直方图结果
可以看到,HE是对整体的直方图做计算和处理,这样的方法灰度分布均匀的图像上处理效果还可以,但对有高峰的直方图处理后,对比度就过分不自然。
AHE是在这个问题的基础上将 计算的范围从整体缩小为局部 。即每个像素通过其周围的一个矩形范围的像素直方图进行均衡化,均衡方式同HE。
当然在图像边缘时,像素是需要特殊处理的,这个通过镜像图像边缘的行像素或列像素来解决。直接复制边缘的像素进行扩充是不合适的。因为这会导致带有剑锋的领域直方图。
亮的地方更亮了,暗的地方更黑了。直方图均衡化使得对比度增强了。均衡化必须建立在灰度图上,因为保持通道单一性。当然彩色图也可以,但是必须制定是哪个通道然后再进行均衡化。
8.2.2 局部均衡化EqualizeHist
并不是说你可以通过参数来控制对比度和范围。
contrast limited adaptive histogram equalization (CLAHE)
createCLAHE([, clipLimit[, tileGridSize]]) -> retval
clipLimit参数表示对比度的大小。
tileGridSize参数表示每次处理块的大小 。
有时候我们不想整个图片调整对比度,所以我们需要局部直方图均衡化。
AHE(Adaptive histogram equalization)是一种用于提升图像对比度的计算机图像处理技术。和普通的直方图均衡算法不同的点在于,它计算那些指定区域的直方图,并用这些值去重新分配图像亮度来改变图像的对比度。
它在每一个小区域内(默认8×8)进行直方图均衡化。当然,如果有噪点的话,噪点会被放大,需要对小区域内的对比度进行了限制。
因此这种方法更适合改进图像的局部对比度和增强图像边缘来获得更多细节。
然而AHE的问题在于对比度增强的同时,也放大了图像的噪音(Noise)一个改进的方法就是CLAHE,即限制对比度的直方图均衡。
clahe方法可以自己控制对比度,比如我们将对比度调的更大一些。比如我们将对比度从 2 ——> 8
8.2.3 直方图比较/获取RGB直方图
直方图比较都是粗略比较。比如我们在图海里面,首先通过直方图比较就能排除掉50%,然后剩下的50%通过其他更加高级的方法来慢慢排除。
对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间
然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进
而比较图像本身的相似程度。Opencv提供的比较方法有四种:
Correlation 相关性比较
Chi-Square 卡方比较
Intersection 十字交叉性
Bhattacharyya distance 巴氏距离
相关性比较 (method=cv.HISTCMP_CORREL) 值越大,相关度越高,最大值为1,最小值为0
卡方比较(method=cv.HISTCMP_CHISQR 值越小,相关度越高,最大值无上界,最小值0
巴氏距离比较(method=cv.HISTCMP_BHATTACHARYYA) 值越小,相关度越高,最大值为1,最小值为0
最好用的方法就是:巴氏距离 + 相关性
直方图是一种像素值分布的概率模型,比如一张灰度图像,像素值0~255,直方图就可以告诉我们像素值为0的点有几个,为1的有几个,为2的有多少个……但是这样太复杂了,运算量太大,因此引入“灰度级”概念,比如0~16的都算作第一级,16~32的都算作第二级……这样横轴只需要16个刻度值就可以表达完整个图像的灰度情况。
那么既然灰度值可以做直方图(一维),那么二维、三维的当然也可以做,原理是一样的。比如可以把R,G,B三个分量分别提取做来做直方图,就可以得到一张图上3条曲线。
其实就是先将原图每个通道提取出来转化为RGB的hist,然后再对比两图片的rgb的hist来确定相似度。(既然能对比rgb的hist,也就能对比HSI或者HSV等等。)
这两个图完全大小一致。直方图比较图片的话,图像大小不一致的话需要对图像大小输出结果做归一化,要么就用图片大小一样的。
8.2.4 直方图的反向投影
直方图反向投影简单的说就是可以通过它来实现图像分割,背景与对象分离,对已知对象位置进行定位。反向投影在模式匹配、对象识别、视频跟踪中均有应用,OpenCV中经典算法之一CAMeanShift就是基于反向投影实现对已知对象的位置查找与标记、从而达到连续跟踪。
视频跟踪,比如空中有一个物体在飞行,我们想追踪他,通过直方图我们可以跟踪它,直方图反向投影是一个关键技术,还有一个关键技术就是均值漂移,漂移到一个地方就计算一个直方图然后和原来的直方图,如果是一样的话就默认找到了该物体。
直方图反向投影首先要得到一个平面的投影。比如地震源定位,手机定位(基站定位,一个基站是不能定位的,要多个基站定位,交线)等等。
直方图反向投影一般都在HSV色彩空间中进行,反向直方图投影都是通过二维直方图进行的,所以首先要获得2D直方图。
8.2.4.1 2D直方图的计算和演示
h = 0-180, s = 0-250; 所以用matplot好用一些。
8.4.2.2 2D直方图的反向投影
直方图反向投影简单的说就是可以通过它来实现图像分割,背景与对象分离,对已知对假设模型图像的颜色直方图为M、目标图像颜色直方图为I、直方图反向投影首先通过计算比率 得到第三个直方图R=M/I,然后根据图像I(x, y)每个像素颜色值的索引查找R得到每个像素点直方图分布概率图像、对图像每个像素点得到I(x,y)=min(Rh(x,y), 1) ,对得到结果图像进行卷积计算,Mask大小默认为3x3或者5x5,形状一般情况下取圆形。对卷积之后的结果计算最大值所在位置即为对象所在位置。此时可以归一化为0~255之间输出图像即可。总结一下可以分为如下几步
先读入图像
转为hsv色彩空间
然后对h-s通道形成一个2D直方图
对2D直方图做一个归一化处理
归一化之后再做反向投影,输出结果,报告。
尝试将输出的结果和原图 做一个“与”操作
因为你的bins越多,就会越细,就会碎片化。[32, 48]。所以很明显所有紫色区域都被追踪到了。最后[0, 180, 0, 256] 这个是绝对不可以动的。就相当与RGB取值为0-255一样。要调只能调整bins的个数。
当你放大很大的时候,就会变成小格子,如果很小很细的话就会变成小点点。下面是32*32的格子。看结果不满意就调整bins,直到满意为止。
8.2.5 模板匹配
所以模板匹配效率不是很高,要一个一个匹配。
确定模板和原图是否匹配有以下这么多算法,平方比较(越小越相似),归一化比较,相关性等等。
现在我们来细看result,最大相关性就是很亮的。越亮代表相关性越高。根据计算结果我们找到数值所在点加上我们的宽高。以0-255的灰度范围标记算法算出来的相关性,目标图像的区域越白,这个区域与template相关性越大。
result图像的大小是减去了模板的宽高,因为模板从中心开始,它作为第一个覆盖的,全覆盖的区域是在左上角,0.5模板的0.5,最后一个模板全部覆盖就是在右下角,也是0.5的0.5,所以最后要减去0.5.