#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/highgui.hpp>
#include "iostream"
#include "func.h"
using namespace cv;
using namespace std;
using namespace xfeatures2d;
#define pi 3.1415926
//使用说明
void Func::attention()
{
printf("[0]表示前一帧,[1]表示当前帧\n\n");
}
//读视频文件
void Func::readVideo(String &videoFile)
{
capture.open(videoFile);
//capture.open(0);
if (!capture.isOpened())
{
cout << "Could not initialize capturing...\n";
system("pause");
}
width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
surfDetector = SURF::create(1000);
}
//读frame
void Func::readFrame()
{
capture.read(cur_frame); //读当前帧
cvtColor(cur_frame, cur_gray, COLOR_BGR2GRAY);
if (prev_gray.empty()) {
cur_gray.copyTo(prev_gray); //更新前一帧
cur_frame.copyTo(prev_frame); //更新前一帧
}
}
//SURF特征检测
void Func::surfDetect()
{
Pts[0].clear(); Pts[1].clear();
desc[0].release(); desc[1].release();
surfDetector->detectAndCompute(prev_gray, Mat(), Pts[0], desc[0]);
surfDetector->detectAndCompute(cur_gray, Mat(), Pts[1], desc[1]);
//drawKeypoints(cur_frame, Pts[1], cur_frame, Scalar(0, 0, 255));
//printf("SURF检测点数:%d、%d \n", Pts[0].size(), Pts[1].size());
}
//KNN匹配
void Func::BfMatch()
{
knnMatches[0].clear();
matcher.knnMatch(desc[0], desc[1], knnMatches[0], 2); //正向匹配
printf("KNN匹配点对数:%d \n", knnMatches[0].size());
//BBF搜索算法
//BBFmatches.clear();
BBFpts[0].clear(); BBFpts[1].clear();
for (size_t i = 0; i < knnMatches[0].size(); i++) {
const DMatch& bestMatch = knnMatches[0][i][0]; //汉明距离最小
const DMatch& betterMatch = knnMatches[0][i][1]; //汉明距离次小
float distanceRatio = bestMatch.distance / betterMatch.distance;
//利用汉明距离粗略过滤匹配点对
if (distanceRatio < minRatio) {
//BBFmatches.push_back(bestMatch);
BBFpts[0].push_back(Pts[0][bestMatch.queryIdx].pt);
BBFpts[1].push_back(Pts[1][bestMatch.trainIdx].pt);
}
}
printf("对称约束前:BBFpts[0].size = %d \n", BBFpts[0].size());
knnMatches[1].clear();
matcher.knnMatch(desc[1], desc[0], knnMatches[1], 2); //反向匹配
BBFpts_rev[0].clear();
BBFpts_rev[1].clear();
for (size_t i = 0; i < knnMatches[1].size(); i++) {
const DMatch& bestMatch_rev = knnMatches[1][i][0]; //汉明距离最小
const DMatch& betterMatch_rev = knnMatches[1][i][1]; //汉明距离次小
float distanceRatio = bestMatch_rev.distance / betterMatch_rev.distance;
//利用汉明距离粗略过滤匹配点对
if (distanceRatio < minRatio) {
//BBFmatches.push_back(bestMatch);
BBFpts_rev[0].push_back(Pts[0][bestMatch_rev.trainIdx].pt);
BBFpts_rev[1].push_back(Pts[1][bestMatch_rev.queryIdx].pt);
}
}
//printf("对称约束前:BBFpts_rev[0].size = %d, BBFpts_rev[1].size = %d \n", BBFpts_rev[0].size(), BBFpts_rev[1].size());
/*printf("---------------------------------------------------------\n");
for (size_t i = 0; i < BBFpts[0].size(); i++)
{
printf("(%d, %d) (%d, %d)\n", BBFpts[0][i].x, BBFpts[0][i].y, BBFpts[1][i].x, BBFpts[1][i].y);
}
printf("~~~~~~~~~~~~~~\n");
for (size_t j = 0; j < BBFpts_rev[0].size(); j++)
{
printf("(%d, %d) (%d, %d)\n", BBFpts_rev[0][j].x, BBFpts_rev[0][j].y, BBFpts_rev[1][j].x, BBFpts_rev[1][j].y);
}
printf("---------------------------------------------------------\n");*/
//对称约束
pts_opti[0].clear(); pts_opti[1].clear();
for (size_t i = 0; i < BBFpts[0].size(); i++)
{
for (size_t j = 0; j < BBFpts_rev[0].size(); j++)
{
//满足对称约束,则跳过
if ((BBFpts[0][i].x == BBFpts_rev[0][j].x) && (BBFpts[0][i].y == BBFpts_rev[0][j].y)) {
if ((BBFpts[1][i].x == BBFpts_rev[1][j].x) && (BBFpts[1][i].y == BBFpts_rev[1][j].y)) {
//位于四角且边界向内10像素范围内的点保留
if (BBFpts[1][i].x >= 20 && BBFpts[1][i].x <= (width - 20) && BBFpts[1][i].y >= 20 && BBFpts[1][i].y <= (height - 20)) {
pts_opti[0].push_back(Point2f(BBFpts[0][i].x, BBFpts[0][i].y));
pts_opti[1].push_back(Point2f(BBFpts[1][i].x, BBFpts[1][i].y));
}
}
}
}
}
printf("对称约束后:pts_opti[1].size = %d \n", pts_opti[1].size());
/*for (size_t i = 0; i < pts_opti[1].size(); i++)
{
printf("(%d, %d) \n", pts_opti[1][i].x, pts_opti[1][i].y);
}
*/
}
/*********************** 待优化 **********************/
//自适应外点滤除
void Func::filtForePts()
{
//获取边角处的特征点
getCornerPts(0.2, 0.2);
if (pts_corner[1].size() < 10) {
getCornerPts(0.3, 0.3);
}
// printf("四角的点数:%d \n", pts_corner[1].size());
//自适应外点滤除
pts_BGD[0].clear(); pts_BGD[1].clear();
pts_FGD[0].clear(); pts_FGD[1].clear();
if (pts_corner[1].size() < 10) { //不做外点滤除
if (pts_corner[1].size() <= 3) {
for (size_t i = 0; i < pts_opti[1].size(); i++)
{
pts_BGD[0].push_back(pts_opti[0][i]);
pts_BGD[1].push_back(pts_opti[1][i]);
}
}
else {
for (size_t i = 0; i < pts_corner[1].size(); i++)
{
pts_BGD[0].push_back(pts_corner[0][i]);
pts_BGD[1].push_back(pts_corner[1][i]);
}
}
}
else { //外点滤除
H = myGetAffineTransform(pts_corner[0], pts_corner[1]); //计算初始 H
cout << "初始 H:" << endl; cout << H << endl;
calcPtsErrs(); //计算距离残差
int errN = ptsErrs.size();
//printf("errN: %d \n", errN);
//迭代min max 距离残差
float minPtsErr = 100.0, maxPtsErr = 0.0;
for (size_t i = 0; i < ptsErrs.size(); i++)
{
float ptsErr = ptsErrs[i];
if (ptsErr > maxPtsErr)
maxPtsErr = ptsErr;
if (ptsErr < minPtsErr)
minPtsErr = ptsErr;
}
//printf("minPtsErr:%.2f, maxPtsErr:%.2f \n", minPtsErr, maxPtsErr);
//ptsErrs_num分配空间
ptsErrs_num.clear();
for (int i = 0; i <= L; i++)
{
ptsErrs_num.push_back(0);
}
float ptsErr_element = (maxPtsErr - minPtsErr) / ((L + 1) * 1.0); //分级因子
if (ptsErr_element != 0.0) {
//统计每级(L)个数
for (size_t i = 0; i < errN; i++)
{
int a = int((ptsErrs[i] - minPtsErr) / ptsErr_element); //商即为级数
//printf(" %d", a);
if (a <= L) {
ptsErrs_num[a]++;
}
else {
ptsErrs_num[L]++;
}
}
//计算距离残差各等级概率
ptsErrs_prob.clear();
for (size_t i = 0; i <= L; i++)
{
ptsErrs_prob.push_back(ptsErrs_num[i] * 1.0 / (errN*1.0));
//printf("%d -- %.2f\n", ptsErrs_num[i], ptsErrs_prob[i]);
//printf("%d ", ptsErrs_num[i]);
}
//printf("\n");
//从0-L之间遍历找到使sigma最大的m
float maxSigma = 0.0;
for (int m = 1; m < L; m++)
{
//计算背景(前景)点集概率和
PtsBGD_prob = 0.0;
PtsFGD_prob = 0.0;
for (size_t i = 0; i <= L; i++)
{
if (i <= m) { //背景
PtsBGD_prob += ptsErrs_prob[i];
}
else if (i > m) { //前景
PtsFGD_prob += ptsErrs_prob[i];
}
}
//计算背景(前景)点集的均值
PtsBGD_aver = 0.0;
PtsFGD_aver = 0.0;
for (size_t i = 0; i <= L; i++)
{
if (i <= m) {
PtsBGD_aver += i * ptsErrs_prob[i] / PtsBGD_prob;
}
else if (i > m) {
PtsFGD_aver += i * ptsErrs_prob[i] / PtsFGD_prob;
}
}
//计算类间方差
float sigma = PtsBGD_prob * pow(PtsBGD_aver, 2) + PtsFGD_prob * pow(PtsFGD_aver, 2);
//更新前(背)景阈值
if (sigma > maxSigma) {
maxSigma = sigma;
th = m;
}
}
//printf("th = %d \n", th);
//分离前景和背景点
for (size_t i = 0; i < errN; i++)
{
if (ptsErrs[i] < ((th + 1)*ptsErr_element + minPtsErr)) {
//背景点
pts_BGD[0].push_back(pts_opti[0][i]);
pts_BGD[1].push_back(pts_opti[1][i]);
}
else {
//前景点
pts_FGD[0].push_back(pts_opti[0][i]);
pts_FGD[1].push_back(pts_opti[1][i]);
}
}
}
}
// printf("背景点:%d, 前景点数:%d \n", pts_BGD[1].size(), pts_FGD[1].size());
float