用直方图统计数据
1、计算图像直方图
bin
直方图是一个简单的表格,表示一幅图像(有时是一组图像)中具有某个值的像素的数量。因此,灰度图像的直方图有 256 个项目,也叫箱子(bin)。0 号箱子提供值为 0 的像素的数量,1 号箱子提供值为 1 的像素的数量,以此类推。很明显,如果把直方图的所有箱子进行累加,得到的结果就是像素的总数。你也可以把直方图归一化,即所有箱子的累加和等于 1。这时,每个箱子的数值表示对应的像素数量占总数的百分比。
cv::calcHist函数
// 用 calcHist 函数计算一维直方图
cv::calcHist(&image, 1, // 仅为一幅图像的直方图
channels, // 使用的通道
cv::Mat(), // 不使用掩码 mask InputArray
hist, // 作为结果的直方图 OutputArray
1, // 这是一维的直方图 dims
histSize, // 箱子数量 const int *
ranges // 像素值的范围 const float **
bool uniform=true
//是否对得到的直方图数组进行归一化处理
bool accumulate=false
//在多个图像时,是否累计计算像素值得个数
cv::minMaxLoc
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
//定义
void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = 0,
//指向返回的最值的指针,NULL为不要求。
Point * minLoc = 0,
Point * maxLoc = 0,
//指向返回最值的位置,NULL为不要求
InputArray mask = noArray()
)
void cv::minMaxLoc ( const SparseMat & a,
double * minVal,
double * maxVal,
int * minIdx = 0,
int * maxIdx = 0
)
cv::line
void cv::line ( InputOutputArray img,
Point pt1,
Point pt2,
const Scalar & color,
int thickness = 1,//线宽
int lineType = LINE_8,//线型
int shift = 0 //小数位数
)
cv::SparseMat
当图像是彩色图像时,可使用数据结构 cv::SparseMat 表示大型稀疏矩阵(即非零元素非常稀少的矩阵),这样不会消耗过多的内存。
cv::SparseMat img(int dims, const int* _sizes, int _type)
//使用数组参数构造函数,与mat类似
//dims为维度,_sizes为数组,表示每个维度大小,数组大小与维度一致
//_type代表的是数据类型,如:CV_8U 、CV_16U 、CV_32F等
2、查找表LUT
查找表是个一对一(或多对一)的函数,定义了如何把像素值转换成新的值。它是一个一维数组,对于规则的灰度图像,它包含 256 个项目。利用查找表的项目 i,可得到对应灰度级的新强度值,如下所示:
newIntensity= lookup[oldIntensity];
OpenCV 中的 cv::LUT 函数在图像上应用查找表生成一个新的图像。查找表通常根据直方图生成
3、直方图均衡化
OpenCV 提供了一个易用的函数,用于直方图均衡化处理。这个函数的调用方式为:
cv::equalizeHist(image,result);
4、归一化
归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。
首先归一化是为了后面数据处理的方便,其次是保证程序运行时收敛加快。归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。归一化有同一、统一和合一的意思。
归一化的目的,是使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系,如大小关系;或是为了作图,原来很难在一张图上作出来,归一化后就可以很方便的给出图上的相对位置等。
void normalize (InputArray src,
InputOutputArray dst,
double alpha=1,
double beta=0,
int norm_type=NORM_L2,
int dtype=-1,
InputArray mask=noArray()
)
e.g.
cv::normalize(histogram,histogram,1.0);
5、反向投影函数calcBackProject
cv::calcBackProject(&image,
1, // 一幅图像
channels, // 用到的通道,取决于直方图的维度
histogram, // 需要反向投影的直方图
result, // 反向投影得到的结果
ranges, // 值的范围
255.0 // 选用的换算系数
// 把概率值从 1 映射到 255
);
6、均值平移算法
// 用均值偏移法搜索物体
cv::TermCriteria criteria(
cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, // 最多迭代 10 次
1); // 或者重心移动距离小于 1 个像素
cv::meanShift(result,rect,criteria);
cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS:
同时满足迭代次数达到最大值(MAX_ITER);窗口中心的偏移值小于某个限值(EPS),可认为该位置收敛到一个稳定点。
cv::meanShift(probImage, window, criteria)
//probImage: 概率分布图像,也就是ROI色调直方图的反向投影
//window: 初始搜索窗口,就是定义ROI的rect
//criteria: 确定窗口搜索停止的准则, 迭代次数达到设置的最大值;窗口中心的漂移值小于某个设定的限值
7、比较直方图计算相似图像
cv::compareHist(refH,inputH, cv::HISTCMP_INTERSECT);
//definition
double cv::compareHist ( InputArray H1,
InputArray H2,
int method
)
方法:
交叉点方法( cv::HISTCMP_INTERSECT )。
卡方测量法(cv::HISTCMP_CHISQR 标志)累加各箱子的归一化平方差;
关联性算法(cv::HISTCMP_CORREL 标志)基于信号处理中的归一化交叉关联操作符测量两个信号的相似度;
Bhattacharyya 测量法(cv::HISTCMP_BHATTACHARYYA 标志)和 Kullback-Leibler发散度(cv::HISTCMP_KL_DIV 标志)
8、积分图像与积分直方图
使用积分图像统计图像感兴趣区域的像素是一种高效的方法。它在程序中的应用非常广泛,例如用于计算基于不同大小的滑动窗口。
自适应阈值化
将每个像素的值与邻域的平均值进行比较。如果某像素的值与它的局部平均值差别很大,就会被当作异常值在阈值化过程中剔除。
因此自适应阈值化需要计算每个像素周围的局部平均值。这需要多次计算图像窗口的累计值,可以通过积分图像提高计算效率。
cv::integral
void cv::integral ( InputArray src,
OutputArray sum,
OutputArray sqsum,
OutputArray tilted,
int sdepth = -1,
int sqdepth = -1
)
src,输入图像 W x H 8位浮点数或者32f,64f;
sum,积分图像必须为(W +1)x(H+1),类型为32位或64位浮点数;
sqsum,平方像素值的积分图像,它是 (W +1)x(H+1)双精度64f数组;
titled,旋转45度的图像积分,它与sum相同数据类型;
sdepth,期望的积分深度和倾斜的积分图像,CV_32S,CV_32F或CV_64F;
sqdepth,要求的深度的积分图像的平方像素值,CV_32F或CV_64F。
e.g.
cv::integral(image,iimage,CV_32S);
自适应阈值化是一种常用的图像处理技术。OpenCV 中也实现了这种方法:
cv::adaptiveThreshold(image, // 输入图像
binaryAdaptive, // 输出二值图像
255, // 输出的最大值
cv::ADAPTIVE_THRESH_MEAN_C, // 方法
cv::THRESH_BINARY, // 阈值类型
blockSize, // 块的大小
threshold); // 使用的阈值
我们也可以用 OpenCV 的图像运算符来编写自适应阈值化过程。具体方法如下所示:
cv::Mat filtered;
cv::Mat binaryFiltered;
// boxFilter 计算矩形区域内像素的平均值
cv::boxFilter(image,filtered,CV_8U,cv::Size(blockSize,blockSize));
// 检查像素是否大于(mean + threshold)
binaryFiltered= image>= (filtered-threshold);