简介
本篇使用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)); }
效果演示
对应的效果演示如下:
时间: 2024-10-16 16:48:38