这一节的运动分析和目标跟踪是提供一些分析图片或图片序列中的固定背景和运动目标的函数。这些函数能够帮助提取出图片序列中的背景和运动目标,可用于处理视频帧,检测视频场景中的运动对象。
(1)、cv::accumulate(InputArray src, InputOutputArray dst,
InputArray mask=noArray())
图像的累加操作函数。这个函数累加src的某些像素到dst:
函数支持多通道图像。每一个通道都单独处理。
函数cv::accumulate 可用于采集和统计静止相机场景中的背景,以及进一步分割背景和前景。
参数
src |
输入图像,类型为CV_8UC(n),CV_16UC(n),CV_32FC(n) 或CV_64FC(n),其中n 为正整数。 |
dst |
累加图像,与输入图像有相同的通道数,深度为CV_32F 或 CV_64F。 |
mask |
可选的操作屏蔽。 |
参见
accumulateSquare, accumulateProduct, accumulateWeighted
(2)、cv::accumulateProduct (InputArray src1, InputArray src2, InputOutputArray dst,
InputArray mask=noArray())
加两个输入图像的像素积到累加图像。这个函数加两个图像的乘积或两个图像选定区域的乘积到累加图像dst:
函数支持多通道图像。每个通道单独处理。
参数
src1 |
第一个输入图像,1- 或3-通道,8-位或32-位浮点类型。 |
src2 |
第二个输入图像,与src1有相同的尺寸和类型。 |
dst |
累加图像,与输入图像有相同数量的同到,32-位或64-位浮点类型。 |
mask |
可选的操作屏蔽。 |
参见
accumulate, accumulateSquare, accumulateWeighted
(3)、cv::accumulateSquare (InputArray src, InputOutputArray dst,
InputArray mask=noArray())
加原图像的平方到累加图像。这个函数加输入图像src的2次幂或它的选定区域的2次幂到累加图像dst:
函数支持多通道图像。每个通道单独处理。
参数
src |
输入图像,有1- 或3-通道,8-位或32-位浮点类型。 |
dst |
累加图像,与输入图像有相同的通道数,32-位或64-位浮点类型。 |
mask |
可选的操作屏蔽。 |
参见
accumulateSquare, accumulateProduct, accumulateWeighted
(4)、cv::accumulateWeighted (InputArray src, InputOutputArray dst,
double alpha, InputArray mask=noArray())
更新连续图像流的平均值。这个函数计算输入图像src与累加图像dst的权重和,使得dst成为帧序列的连续平均值图像:
此时,alpha 用来调节更新速率(累加器有多快来“忘记”较早的图像)。这个函数支持多通道图像,每个通道单独处理。
参数
Src |
输入图像,具有1- 或 3-通道,8-位或32-位浮点类型。 |
dst |
累加图像,与输入图像有相同的通道数,32-位或64-位浮点类型。 |
alpha |
输入图像的权重。 |
mask |
可选的操作屏蔽。 |
参见
accumulate, accumulateSquare, accumulateProduct
(5)、cv::createHanningWindow (OutputArray dst, Size winSize, int type)
这个函数计算二维汉宁窗系数。细节参考相关资料。例子如下:
//建立一个类型为CV_32F,尺寸为100x100的汉宁窗
Mat hann;
createHanningWindow(hann, Size(100, 100), CV_32F);
参数
dst |
存储汉宁窗系数的目标数组。 |
winSize |
指定的窗口尺寸(宽和高二者都必须 > 1)。 |
type |
建立的数组类型。 |
(6)、cv::phaseCorrelate (InputArray src1, InputArray src2,
InputArray window=noArray(), double *response=0)
这个函数用于检测发生在两个图像之间的平移。这个操作利用傅里叶变换定理检测频域上的平移。它可用于快速图像校准和运动评估。更多信息请参考相关资料。
计算所提供的两个源数组的互功率谱,如果必要,这两个源数组使用getOptimalDFTSize连接到一起。这个函数执行下列方程:
此处是前馈DFT.
参数
src1 |
源浮点数组(CV_32FC1 或 CV_64FC1)。 |
src2 |
源浮点数组(CV_32FC1 或 CV_64FC1)。 |
window |
具有窗系数的浮点数组,用于减少边缘效应(可选)。 |
response |
在峰值周围5x5质心范围内的信号功率,在0 和1之间(可选)。 |
返回
检测到的两数组之间的相移(亚像素级)。
参见
dft, getOptimalDFTSize, idft, mulSpectrums createHanningWindow
运动分析和目标跟踪(Motion Analysis and Object Tracking)编程实例
运动分析主要是使用图像累加方式检测图片系列的背景和移动的前景。通过不断地叠加过滤,不运动的背景被增强,运动的前景被削弱,然后通过对图片的阈值处理,获得运动物的位置。
1、cv::accumulate(InputArray src, InputOutputArray dst,
InputArray mask=noArray())
cv::accumulateProduct (InputArray src1, InputArray src2, InputOutputArray dst,
InputArray mask=noArray())
cv::accumulateSquare (InputArray src, InputOutputArray dst,
InputArray mask=noArray())
cv::accumulateWeighted (InputArray src, InputOutputArray dst,
double alpha, InputArray mask=noArray())
求图像的累加和函数,其中包括,累加平均,乘积累加,平方累加和权重累加,分别对原图像进行指定操作后累加到累加器图像上,形成新的累加图像。
源图像,操作图像,使用accumulateWeight()函数,weight = 0.6,进行权重累加,从图中可以看出,每次累加源图的背景变淡,直至消失,说明在帧流图像中静止背景总是会自动形成,运动前景会逐渐消失。用背景与前景的差分图像可以正确地跟踪运动目标。
通过对捕捉图像进行处理:
cv::cvtColor(image,image1,CV_RGB2GRAY);//灰度变换采集图像
cv::GaussianBlur(image1, image1, Size(5,5), 1.5, 1.5);//高斯滤波
cv::absdiff(image1,imageBackground,imageFront);//差分图像与背景,获得前景图像(运动部分)
imageBackground.convertTo(imageBackground,CV_32FC1); //扩展至32位做运算
cv::accumulateWeighted(image1,imageBackground,accweight,imageFront);//权重累加
imageBackground.convertTo(imageBackground,CV_8UC1); //转换回8位
cv::threshold(imageFront,imageFront,0,255,CV_THRESH_OTSU); //阈值分割
//开运算和膨胀都是降低灵敏度的算法,对于小的运动目标不敏感
cv::morphologyEx(imageFront, imageFront, CV_MOP_OPEN, element);//消除孤立的点
cv::dilate(imageFront,imageFront,element);//膨胀操作,消除孔洞
注意:前景图像的滤波处理,可能会影响到运动部分的敏感度,重处理会降低敏感度,轻处理会增加噪声。因此需要在实际使用中寻找平衡点。另外,可以使用其它图像特征来定位运动前景。
2、cv::phaseCorrelate (InputArray src1, InputArray src2,
InputArray window=noArray(), double *response=0)
cv::createHanningWindow (OutputArray dst, Size winSize, int type)
图像的平行移动(平移)通过phaseCorrelate函数可以给出亚像素级精度的移动位置度量。对于精确的目标跟踪定位有一定的意义。在视频的运动目标跟踪过程中对accumulateWeight处理过后的运动前景进行phaseCorrelate计算,可以给出运动方向和距离数据。
对于视频运动图像,计算两帧之间的移动量,图像显示,110ms之间手的移动x=0.168745,y=1.58193。正数为向右上移动,负数为向左下移动。汉宁窗的使用可以减少窗口的边缘效应。
videoCap>>image;//帧图像
Mat image1, imageFrt;
cv::cvtColor(image,image1,CV_RGB2GRAY);//灰度变换采集图像
cv::GaussianBlur(image1, image1, Size(5,5), 1.5, 1.5);//高斯滤波
cv::absdiff(image1,imageBackground, imageFrt);//差分图像与背景,获得前景图像(运动部分)
cv::GaussianBlur(imageFrt, imageFrt, Size(5,5), 1.5, 1.5);//高斯滤波
imageBackground.convertTo(imageBackground,CV_32FC1);
cv::accumulateWeighted(image1,imageBackground, 0.6, imageFrt);
imageBackground.convertTo(imageBackground,CV_8UC1); //转换回8位
cv::threshold(imageFrt, imageFrt,0,255,CV_THRESH_OTSU); //阈值分割
cv::morphologyEx(imageFrt, imageFrt, CV_MOP_OPEN, element);
cv::dilate(imageFrt,imageFrt,element);
cv::dilate(imageFrt,imageFrt,element);
if (frontImg.empty()){
frontImg = imageFrt.clone();
frontImg.convertTo(frontImg, CV_32FC1);
}
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
vector<Point> accAllcontours;
cv::findContours(imageFrt,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
for(size_t i=0;i<contours.size();i++){
for (size_t j = 0; j < contours[i].size(); j++){
accAllcontours.push_back(contours[i].at(j));
}
}
RotatedRect rect=cv::minAreaRect(accAllcontours);
Point2f P[4];
rect.points(P);
for(int j=0;j<=3;j++){
line(image,P[j],P[(j+1)%4],Scalar(0,255,255),2);
}
//
imageFrt.convertTo(imageFrt, CV_32FC1);
Point2f shftP;
if (hanning){
shftP = cv::phaseCorrelate(imageFrt, frontImg, hanningwin);
}else{
shftP = cv::phaseCorrelate(imageFrt, frontImg);
}
frontImg = imageFrt.clone();
//显示数据
ostringstream intv;
intv << val;
intv << " x = ";
intv << shftP.x;
intv << " y = ";
intv << shftP.y;
//
cv::putText(image, intv.str(), Point(20,20), 1, 1, Scalar(255,0,255), 2);
注意:hanningwin是初始化时生成的,accAllcontours是为了计算运动目标的总外围矩形而生成的。frontImg = imageFrt.clone();则是保留当前前景图像,便于与下一帧进行比较(初始为背景图)。