opencv实现移动速度计算

简介

  本篇使用opencv函数phaseCorrelate来计算video录像时候移动速度和方向或者说是摄像头当前移动速度和方向。

phaseCorrelate

  Point2d phaseCorrelate(InputArray src1, InputArray src2, InputArray window=noArray())
    src1:前一帧video图像;
    src2:当前video图像;
    window:浮点阵列的窗口系数,用来减少边缘效应(可选)。
    返回的Point2d:返回的二维坐标,x表示src2相对于src1在X轴上移动的距离,y表示src2相对于src1在Y轴上移动的距离;

实例讲解

具体代码

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
 
using namespace cv;
 
int main(int argc, char* argv[])
{
    VideoCapture video(argv[1]);
    Mat frame, curr, prev, curr64f, prev64f, hann;
	int key = 0;
	Mat imageROI;
	CvFont font;    
	double hScale=1;   
	double vScale=1;    
	int lineWidth=1;
	char showMsg[20];
 
	cvInitFont(&font,  CV_FONT_HERSHEY_PLAIN|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);
    do
    {
        video >> frame;
        cvtColor(frame, curr, COLOR_RGB2GRAY);
 
        if(prev.empty()){
            prev = curr.clone();
            createHanningWindow(hann, curr.size(), CV_64F);
        }
 
		if(curr.empty()){
			break;	
		}
        prev.convertTo(prev64f, CV_64F);
        curr.convertTo(curr64f, CV_64F);
 
        Point2d shift = phaseCorrelate(prev64f, curr64f, hann);
        double radius = cv::sqrt(shift.x*shift.x + shift.y*shift.y);
 
        if(radius > 5){
			int width = curr.cols;
			int height = curr.rows;
			Point center(50, 40);
			printf("radius:%lf\n", radius);
			if((width < 100) && (height < 100)){
				printf("image size is too small!!!\n");
				break;
			}
			imageROI = frame(cv::Rect((width - 100), 5, 95, 100));
			IplImage img = imageROI;
			cvZero(&img);
			circle(imageROI, center, (int)radius, cv::Scalar(0, 255, 0), 1, CV_AA);
			line(imageROI, center, Point(center.x + (int)shift.x, center.y + (int)shift.y), cv::Scalar(0, 255, 0), 1, CV_AA);
			sprintf(showMsg, "x:%d", -(int)shift.x);
			cvPutText(&img, showMsg ,cvPoint(10,85),&font,CV_RGB(255,0,0));
			sprintf(showMsg, "y:%d", -(int)shift.y);
			cvPutText(&img, showMsg ,cvPoint(10,97),&font,CV_RGB(255,0,0));
 
        }
 
        imshow("phase shift", frame);
        key = waitKey(20);
		if(key == 'q'){
			break;
		}
 
        prev = curr.clone();
    } while((char)key != 27);
 
    return 0;
}

代码讲解

  1、首先用cvInitFont初始化字体显示,接着在一个循环中,不停的依次读取每帧video数据,然后将前一帧和当前帧数据,转化格式为CV_64F,
然后传入phaseCorrelate中进行处理,接着用sqrt计算出返回相对位移坐标shift的平方根radius,如果radius小于5,则表示移动距离太短。直接跳过
处理流程,然后显示出当前帧数据,最后注意用当前帧数据更新前一帧数据。
cvInitFont(&font,  CV_FONT_HERSHEY_PLAIN|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);
    do
    {
        video >> frame;
        cvtColor(frame, curr, COLOR_RGB2GRAY);
 
        if(prev.empty()){
            prev = curr.clone();
            createHanningWindow(hann, curr.size(), CV_64F);
        }
 
		if(curr.empty()){
			break;	
		}
        prev.convertTo(prev64f, CV_64F);
        curr.convertTo(curr64f, CV_64F);
 
        Point2d shift = phaseCorrelate(prev64f, curr64f, hann);
        double radius = cv::sqrt(shift.x*shift.x + shift.y*shift.y);
 
        if(radius > 5){
            ............
        }
 
        imshow("phase shift", frame);
        key = waitKey(20);
		if(key == 'q'){
			break;
		}
 
        prev = curr.clone();
    } while((char)key != 27);
  2、如果radius大于5,就在图像的右上角,用imageROI取一块100x100的矩形,接着在里面根据之前获得的位移坐标shift,画出一条直线和一个圆,
来表示当前移动的速度,接着在矩形框最下面,显示出X和Y上,相对移动的距离。
        if(radius > 5){
		int width = curr.cols;
		int height = curr.rows;
		Point center(50, 40);
		printf("radius:%lf\n", radius);
		if((width < 100) && (height < 100)){
			printf("image size is too small!!!\n");
			break;
		}
		imageROI = frame(cv::Rect((width - 100), 5, 95, 100));
		IplImage img = imageROI;
		cvZero(&img);
		circle(imageROI, center, (int)radius, cv::Scalar(0, 255, 0), 1, CV_AA);
		line(imageROI, center, Point(center.x + (int)shift.x, center.y + (int)shift.y), cv::Scalar(0, 255, 0), 1, CV_AA);
		sprintf(showMsg, "x:%d", -(int)shift.x);
		cvPutText(&img, showMsg ,cvPoint(10,85),&font,CV_RGB(255,0,0));
		sprintf(showMsg, "y:%d", -(int)shift.y);
		cvPutText(&img, showMsg ,cvPoint(10,97),&font,CV_RGB(255,0,0)); 
        }

效果演示

 对应的效果演示如下:
                             
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值