OpenCV的Sample分析:real_time_tracking(5)
在之前的分析中,了解了三个比较重要的类kalman,类PnPProblem,以及类RobustMatcher
今天继续分析main函数,
KalmanFilter KF; // instantiate Kalman Filter int nStates = 18; // the number of states int nMeasurements = 6; // the number of measured states int nInputs = 0; // the number of control actions double dt = 0.125; // time between measurements (1/FPS) initKalmanFilter(KF, nStates, nMeasurements, nInputs, dt); // init function Mat measurements(nMeasurements, 1, CV_64F); measurements.setTo(Scalar(0)); bool good_measurement = false; // Get the MODEL INFO vector<Point3f> list_points3d_model = model.get_points3d(); // list with model 3D coordinates Mat descriptors_model = model.get_descriptors(); // list with descriptors of each 3D coordinate
这段代码交代了状态变量,观测变量以及控制变量的个数,分别是18,6,0
把模型中“角点”的3D坐标赋给vector<Point3f>变量list_points3d_model,并且把角点相应的描述子信息赋值给Mat类变量descriptors_model
setTo函数是什么意思呢?CSDN大牛是这样答复的点击打开链接:
opencv的setTo函数是将图像设置为某个值,比如有一个Mat src,想将他的值全部设置成0,则可以src.setTo(0)
另外,setTo还有更为高级的用法,比如,对于一个已知的src,我们要将其中大于或者小于某个值的像素值设置为指定的值,则可以如下:
src.setTo(0,src < 10);
这句话的意思是,当src中的某个像素值小于10的时候,就将该值设置成0.
还有一点,这是自己猜想的,前面的那个0可以换成另一个图像:
src.setTo(dst,src < 10);
这里的意思是,对于src中的像素值,当其值小于10的时候,就将该值用dst中相应位置的值进行替换。
下面是加载一段视频的代码,
namedWindow("REAL TIME DEMO", WINDOW_KEEPRATIO); VideoCapture cap; // instantiate VideoCapture cap.open(video_read_path); // open a recorded video if(!cap.isOpened()) // check if we succeeded { cout << "Could not open the camera device" << endl; return -1; }
对nameWindow以及VideoCapture不陌生吧
// start and end times time_t start, end; // fps calculated using number of frames / seconds // floating point seconds elapsed since start double fps, sec; // frame counter int counter = 0; // start the clock time(&start); Mat frame, frame_vis; while(cap.read(frame) && (char)waitKey(30) != 27) // capture frame until ESC is pressed { frame_vis = frame.clone(); // refresh visualisation frame //.......................... }
从这一段基本代码,可以学到一些东西:
(1)常见的计时方式
(2)初始化一个Mat类frame,常见的视频读取的while语句
(3)用frame_vis,起到保护frame的作用
现在正式分析while语句的第一部分,
第一步,特征点匹配
// -- Step 1: Robust matching between model descriptors and scene descriptors vector<DMatch> good_matches; // to obtain the 3D points of the model vector<KeyPoint> keypoints_scene; // to obtain the 2D points of the scene if(fast_match) { rmatcher.fastRobustMatch(frame, good_matches, keypoints_scene, descriptors_model); } else { rmatcher.robustMatch(frame, good_matches, keypoints_scene, descriptors_model); }
首先要注意到“model descriptors”以及“scene descriptors”的意思,为了理解其中的意思,需要分析robustMatch这个函数,在这个函数中,frame指视频中这一帧的图像,good_matchs指盒子模型角点的3D坐标,keypoints_scene指相应角点在像素坐标系下的坐标,descriptors_model指盒子模型角点的描述子
void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector<cv::DMatch>& good_matches, std::vector<cv::KeyPoint>& keypoints_frame, const cv::Mat& descriptors_model ) { // 1a. Detection of the ORB features this->computeKeyPoints(frame, keypoints_frame); // 1b. Extraction of the ORB descriptors cv::Mat descriptors_frame; this->computeDescriptors(frame, keypoints_frame, descriptors_frame); // 2. Match the two image descriptors std::vector<std::vector<cv::DMatch> > matches12, matches21; // 2a. From image 1 to image 2 matcher_->knnMatch(descriptors_frame, descriptors_model, matches12, 2); // return 2 nearest neighbours // 2b. From image 2 to image 1 matcher_->knnMatch(descriptors_model, descriptors_frame, matches21, 2); // return 2 nearest neighbours // 3. Remove matches for which NN ratio is > than threshold // clean image 1 -> image 2 matches ratioTest(matches12); // clean image 2 -> image 1 matches ratioTest(matches21); // 4. Remove non-symmetrical matches symmetryTest(matches12, matches21, good_matches); }
似乎有点复杂,但是值得深入了解(opencv的注释极大方便了使用者的学习!)
可以发现,特征点匹配需要以下几步:
(1)提取frame这一帧的特征点,并且获取该特征点的描述子
(2)建立从frame特征点到descriptors_model特征点的单射关系
建立从descriptors_model特征点到frame特征点的单射关系
(3)寻找其中的双射关系,把双射的特征点保留下来
fastRobustMatch其实比RobustMatch少了一些罗嗦步骤,所以快一些嘛
第二步,建立2D点到3D点的匹配关系,由于时间的关系,放到下次再说