无人机目标定位C++程序

针对动态背景下的目标检测定位
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/stitching/stitcher.hpp>
#include<iostream>
#include<vector>
#include<Windows.h>
#include<sstream>
#include<time.h>
#include<fstream>
#include<math.h>

using namespace cv;
using namespace std;

//定义全局变量
Rect pre_Rect;//定义初始帧的框
int shrink = 4;//图片帧缩小倍数
int frame_num = 1;//记录循环帧数
ofstream recordFile("E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\纪录处理时间.txt");//创建记录文件



//运动物体检测函数声明  
Mat MoveDetect(Mat temp, Mat frame);
//基于特征点匹配的图像拼接
void stitch(Mat& srcImage1, Mat& srcImage2, Mat& panorama);
//读入视频帧   调用stitch2函数进行拼接
void readVideo(string videoName);
//求矩形的中心点
Point getCenterPoint(Rect rect);
//获取两点间的距离
double getDistance(Point p1, Point p2);
//手动标框
void onMouse(int event, int x, int y, int, void *);


int main(int argc, char* argv[]) {
    //pre_Rect = Rect(Point(1050, 520), Point(1160, 580));//自己设定的初始矩形框
    pre_Rect = Rect(Point(260, 130), Point(300, 150));//自己设定的初始矩形框
    readVideo("E:\\软件所资料\\录制视频\\test.mov");
    return 0;
}


//读入视频帧   调用stitch函数进行拼接
void readVideo(string videoName) {

    VideoCapture videoCap(videoName);
    if (!videoCap.isOpened()) {
        exit;
    }
    Mat preFrame;//先前帧
    Mat nowFrame;//当前帧
    Mat stichFrame;//拼接帧
    Mat resultFrame;//结果帧

    //函数回调   鼠标事件
    namedWindow("result", 1);
    setMouseCallback("result", onMouse, 0);

    clock_t start, finish, all_start, all_finish;//计算程序运行时间
    double processTime, totalTime = 0;
    videoCap >> preFrame;
    GaussianBlur(preFrame, preFrame, Size(5, 5), 0, 0);//高斯滤波器去除图像中噪点
    resize(preFrame, preFrame, Size(preFrame.cols / shrink, preFrame.rows / shrink));
    //imshow("first", preFrame);
    //int count = 1;
    while (true) {
        all_start = clock();//纪录总的开始时间
        videoCap >> nowFrame;
        GaussianBlur(nowFrame, nowFrame, Size(5, 5), 0, 0);//高斯滤波器去除图像中噪点
        if (nowFrame.empty()) {
            recordFile << "平均处理时间:" << totalTime / frame_num << "ms" << "\n" << "\n";
            recordFile.close();
            break;
        }
        resize(nowFrame, nowFrame, Size(nowFrame.cols / shrink, nowFrame.rows / shrink));

        recordFile << frame_num++ << "\n";

        Mat temp;
        start = clock();
        stitch(nowFrame, preFrame, temp);
        finish = clock();
        recordFile << "拼接用时:" << finish - start << "ms" << "\n";

        if (temp.empty()) {
            stichFrame = nowFrame;
        }
        else {
            stichFrame = temp;
        }


        start = clock();
        resultFrame = MoveDetect(nowFrame, stichFrame);
        finish = clock();
        recordFile << "减差和检测用时:" << finish - start << "ms" << "\n";

        all_finish = clock();//纪录总的结束时间
        processTime = all_finish - all_start;
        recordFile << "共运行:" << processTime << "ms" << "\n" << "\n";
        totalTime += processTime;


        //拼接字符串
        String imageName = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\第";//字符串检测图片名称
        //数字转换成字符串
        ostringstream strCount;
        strCount << frame_num;
        string str = strCount.str();
        imageName.append(str);
        imageName.append("帧图片.jpg");
        imwrite(imageName, resultFrame);

        imshow("result", resultFrame);
        waitKey(1);
        preFrame = nowFrame.clone();//当前帧nowFrame赋给上一帧preFrame;

    }
}


//基于特征点匹配的图像拼接
void stitch(Mat& srcImage1, Mat& srcImage2, Mat& panorama) {
    clock_t start;
    clock_t finish;
    start = clock();
    Mat srcImage2Warped;
    //SURF特征点描述
    int minHessian = 400; //Hessian海塞矩阵阈值 原值400,在这里调整精度,值越大点越小,越精准
    SurfFeatureDetector detector(minHessian);
    vector<KeyPoint> kPointMat, kPointMat2;
    detector.detect(srcImage1, kPointMat);
    detector.detect(srcImage2, kPointMat2);
    //计算特征向量
    SurfDescriptorExtractor extractor;
    Mat desMat1, desMat2;//存放特征向量的矩阵
    extractor.compute(srcImage1, kPointMat, desMat1);
    extractor.compute(srcImage2, kPointMat2, desMat2);


    ////ORB特征点检测
    //ORB orb;
    //vector<KeyPoint> kPointMat, kPointMat2;
    //orb.detect(srcImage1,kPointMat);
    //orb.detect(srcImage2, kPointMat2);

    finish = clock();
    cout << "特征点检测时间" << finish - start << endl;
    start = clock();
    //FLANN关键点匹配
    //FLANN初始化、RANSAC一致性、最近邻特征
    BFMatcher matcher;
    vector<DMatch> matches;
    matcher.match(desMat1, desMat2, matches);
    double min_dist = 100 * 1.0 / shrink;
    //double max_dist = 0;
    //特征点最大与最小距离查找
    for (int i = 0; i < desMat1.rows; i++) {
        double dist = matches[i].distance;
        if (dist < min_dist) min_dist = dist;
        //if (dist > max_dist) max_dist = dist;
    }
    //使用good特征构建距离限定
    vector<DMatch> good_matches;
    for (int i = 0; i < desMat1.rows; i++) {
        //特征点最优距离筛选
        if (matches[i].distance < 3 * min_dist) {  //距离筛选  原值3*min_dist
            good_matches.push_back(matches[i]);
        }
    }
    //图像的关键点匹配
    vector<Point2f> srcImage1_matchedKPs;
    vector<Point2f> srcImage2_matchedKPs;
    for (size_t i = 0; i < good_matches.size(); i++) {
        srcImage1_matchedKPs.push_back(kPointMat[good_matches[i].queryIdx].pt);
        srcImage2_matchedKPs.push_back(kPointMat2[good_matches[i].trainIdx].pt);
    }

    finish = clock();
    cout << "关键点匹配时间" << finish - start << endl;//关键点匹配

    try {
        start = clock();
        //计算图像1与图像2的映射
        Mat H = findHomography(Mat(srcImage2_matchedKPs), Mat(srcImage1_matchedKPs), CV_RANSAC);
        //仿射变换
        warpPerspective(srcImage2, srcImage2Warped, H, Size(srcImage2.cols, srcImage2.rows), INTER_CUBIC);
        //imshow("srcImage2Warped", srcImage2Warped);
        panorama = srcImage2Warped.clone();


        //写入结合帧图片
        //拼接字符串
        String imageName = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\结合帧\\第";//字符串检测图片名称
        //数字转换成字符串
        ostringstream strCount;
        strCount << frame_num;
        string str = strCount.str();
        imageName.append(str);
        imageName.append("帧图片.jpg");
        imwrite(imageName, panorama);

        finish = clock();
        cout << "仿射变换时间" << finish - start << endl;//关键点匹配
        cout << endl;
    }
    catch (Exception e) {
        exit;
    }


}


//Point pt1 = Point(260, 130), pt2 = Point(290, 150);
//帧差和目标检测
Mat MoveDetect(Mat temp, Mat frame)
{
    Mat result = temp.clone();
    //1.将background和frame转为灰度图  
    Mat gray1, gray2;
    cvtColor(temp, gray1, CV_BGR2GRAY);
    cvtColor(frame, gray2, CV_BGR2GRAY);
    //2.将background和frame做差  
    Mat diff = Mat::zeros(temp.rows, temp.cols, CV_8UC1);

    cvtColor(temp, temp, CV_RGB2GRAY);
    cvtColor(frame, frame, CV_RGB2GRAY);

    //写入结合帧灰度图
    //拼接字符串
    String imageName = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\结合帧灰度图\\第";//字符串检测图片名称
    //数字转换成字符串
    ostringstream strCount;
    strCount << frame_num;
    string str = strCount.str();
    imageName.append(str);
    imageName.append("帧图片.jpg");
    imwrite(imageName, frame);


    //写入普通帧灰度图
    //拼接字符串
    String imageName1 = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\普通帧灰度图\\第";//字符串检测图片名称
    //数字转换成字符串
    ostringstream strCount1;
    strCount1 << frame_num;
    string str1 = strCount1.str();
    imageName1.append(str1);
    imageName1.append("帧图片.jpg");
    imwrite(imageName1, temp);


    //膨胀  去原图像毛边
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));//原数值为3,3
    dilate(temp, temp, element);
    dilate(frame, frame, element);

    //帧差法 直接灰度值相减
    for (int i = 0; i < diff.cols - 1; i++)
    {
        for (int j = 0; j < diff.rows - 1; j++)
        {
            int t1 = 20, t2 = 200;
            if (temp.at<uchar>(j, i) - frame.at<uchar>(j, i) >= t1 && temp.at<uchar>(j, i) - frame.at<uchar>(j, i) <= t2)
            {
                diff.at<uchar>(j, i) = 255;//temp.at<uchar>(j, i) - frame.at<uchar>(j, i);
            }
            else if (frame.at<uchar>(j, i) - temp.at<uchar>(j, i) >= t1 && frame.at<uchar>(j, i) - temp.at<uchar>(j, i) <= t2)
            {
                diff.at<uchar>(j, i) = 255;//frame.at<uchar>(j, i) - temp.at<uchar>(j, i);
            }
        }
    }


    //写入帧差后灰度图
    //拼接字符串
    String imageName2 = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\帧差后灰度图\\第";//字符串检测图片名称
    //数字转换成字符串
    ostringstream strCount2;
    strCount2 << frame_num;
    string str2 = strCount2.str();
    imageName2.append(str2);
    imageName2.append("帧图片.jpg");
    imwrite(imageName2, diff);



    ////获取自定义核
    //Mat element1 = getStructuringElement(MORPH_RECT, Size(2, 2)); //MORPH_RECT 原数值Size(2,2) 第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的 
    ////腐蚀操作
    //morphologyEx(diff, diff, MORPH_OPEN, element1);//开运算  先腐蚀后膨胀  去除小的物体


    Mat element1 = getStructuringElement(MORPH_RECT, Size(3, 3)); //MORPH_RECT 原数值Size(2,2) 第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的 
    dilate(diff, diff, element1, Point(-1, -1), 3);

    //写入帧差和形态学处理后灰度图
    //拼接字符串
    String imageName3 = "E:\\软件所资料\\科创项目材料\\图片\\all_pic3(1.2)\\帧差和形态学处理后灰度图\\第";//字符串检测图片名称
    //数字转换成字符串
    ostringstream strCount3;
    strCount3 << frame_num;
    string str3 = strCount3.str();
    imageName3.append(str3);
    imageName3.append("帧图片.jpg");
    imwrite(imageName3, diff);


    /*for (int j = pt1.y + 5; j > pt1.y - 5; j--)
    {
        int flag = 0;
        for (int i = pt1.x; i < pt2.x; i++)
        {
            if (diff.at<uchar>(j, i) > 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
        {
            pt1.y = j;
            break;
        }
    }
    for (int j = pt2.y - 5; j < pt2.y + 5; j++)
    {
        int flag = 0;
        for (int i = pt1.x; i < pt2.x; i++)
        {
            if (diff.at<uchar>(j, i) > 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
        {
            pt2.y = j;
            break;
        }
    }
    for (int i = pt1.x + 5; i > pt1.x - 5; i--)
    {
        int flag = 0;
        for (int j = pt1.y; j < pt2.y; j++)
        {
            if (diff.at<uchar>(j, i) > 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
        {
            pt1.x = i;
            break;
        }
    }
    for (int i = pt2.x - 5; i < pt2.x + 5; i++)
    {
        int flag = 0;
        for (int j = pt1.y; j < pt2.y; j++)
        {
            if (diff.at<uchar>(j, i) > 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
        {
            pt2.x = i;
            break;
        }
    }
    cout << pt1 << pt2 << endl;
    Mat diff1 = diff.clone();
    cvtColor(diff1, diff1, CV_GRAY2RGB);
    line(diff1, Point(pt1.x, pt1.y), Point(pt2.x, pt1.y), Scalar(0, 0, 255), 1, 8);
    line(diff1, Point(pt1.x, pt2.y), Point(pt2.x, pt2.y), Scalar(0, 0, 255), 1, 8);
    line(diff1, Point(pt1.x, pt1.y), Point(pt1.x, pt2.y), Scalar(0, 0, 255), 1, 8);
    line(diff1, Point(pt2.x, pt1.y), Point(pt2.x, pt2.y), Scalar(0, 0, 255), 1, 8);
    imwrite(imageName3, diff1);*/


    //6.查找轮廓并绘制轮廓  
    vector<vector<Point> > contours;
    findContours(diff, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    //drawContours(result, contours, -1, Scalar(0, 0, 255), 2);//在result上绘制轮廓  
    //7.查找正外接矩形  
    vector<Rect> boundRect(contours.size());

    int pre_Rect_width = (pre_Rect.br().x - pre_Rect.tl().x);//上一个目标框的宽
    int pre_Rect_height = (pre_Rect.br().y - pre_Rect.tl().y);//上一个目标框的高

    int pre_Rect_x = pre_Rect.tl().x + pre_Rect_width / 2, pre_Rect_y = pre_Rect.tl().y + pre_Rect_height / 2;//上一个位置的中心点

    //在上一个矩形标注框的3*3的区域搜索矩形
    int search_lt_x = pre_Rect.tl().x - 1.0 * pre_Rect_width;//左上角点的x值
    int search_lt_y = pre_Rect.tl().y - 1.0 * pre_Rect_height;//左上角点的y值
    int search_br_x = pre_Rect.br().x + 1.0 * pre_Rect_width;//右下角点的x值
    int search_br_y = pre_Rect.br().y + 1.0 * pre_Rect_height;//右下角的y值
    Point search_lt = Point(search_lt_x, search_lt_y);//左上角点
    Point search_br = Point(search_br_x, search_br_y);//右下角点
    Rect search_Rect = Rect(search_lt, search_br);//搜索矩形
    vector<Rect> search_area_boundRect(contours.size());
    int search_rect_count = 0;//搜索区域内的矩形数量

    //遍历所有的轮廓矩形 挑选出搜索区域内的轮廓矩形加入到search_area_boundRect可变数组中
    for (int i = 0; i < contours.size(); i++)
    {
        boundRect[i] = boundingRect(contours[i]);//边缘矩形赋值给定义的矩形数组元素
        if (boundRect[i].tl().y < (50 * 1.0 / shrink) || boundRect[i].tl().x < (50 * 1.0 / shrink) || boundRect[i].br().x>(1700 * 1.0 / shrink) || boundRect[i].br().y>(900 * 1.0 / shrink)) {//去除边缘矩形
            continue;
        }
        //判断矩形相交或搜索矩形包含轮廓矩形 条件1-4满足任意一个即可判断其相交或包含
        bool limit1 = (boundRect[i].tl().x > search_lt_x&&boundRect[i].tl().x < search_br_x) && (boundRect[i].tl().y > search_lt_y&&boundRect[i].tl().y < search_br_y); //该矩形左上角在搜索区域内
        //用轮廓矩形左上角的y右下角的x值代替右上角的值
        int boundRect_rt_x = boundRect[i].br().x;
        int boundRect_rt_y = boundRect[i].tl().y;
        bool limit2 = (boundRect_rt_x > search_lt_x&&boundRect_rt_x < search_br_x) && (boundRect_rt_y > search_lt_y&&boundRect_rt_y < search_br_y);//该矩形右上角在搜索区域内
        bool limit3 = (boundRect[i].br().x > search_lt_x&&boundRect[i].br().x < search_br_x) && (boundRect[i].br().y > search_lt_y&&boundRect[i].br().y < search_br_y); //该矩形右下角在搜索区域内
        //用轮廓的矩形左上角的x右下角的y值代替左下角的值
        int boundRect_bl_x = boundRect[i].tl().x;
        int boundRect_bl_y = boundRect[i].br().y;
        bool limit4 = (boundRect_bl_x > search_lt_x&&boundRect_bl_x < search_br_x) && (boundRect_bl_y > search_lt_y&&boundRect_bl_y < search_br_y);//该矩形右上角在搜索区域内

        if (limit1 || limit2 || limit3 || limit4) {
            if (boundRect[i].width < 3 * boundRect[i].height&&boundRect[i].height < 3 * boundRect[i].width) {//去除长条的矩形
                //求该矩形中心到上一个定位框中心点距离 挑出小于上一个对角线一半的矩形框
                Point boundRectCenterPoint = getCenterPoint(boundRect[i]);
                Point preRectCenterPoint = getCenterPoint(pre_Rect);
                double dis = getDistance(boundRectCenterPoint, preRectCenterPoint);
                //求上一个矩形定位框对角线一半的距离
                double diagonal = sqrt(pow(pre_Rect.width, 2) + pow(pre_Rect.height, 2));//对角线的距离
                if (dis <= diagonal / 2) {
                    search_area_boundRect[search_rect_count++] = boundRect[i];//找出矩形搜索区域内的所有轮廓矩形放入可变数组中
                }
                rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制选出的搜索区域内的正外接矩形
            }
        }

        //rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形
        rectangle(result, search_Rect, Scalar(255, 0, 0), 2);
    }
    //如果在距离上一个定位框中心点的距离小于对角线一半的矩形一个都没有   则扩大区域在搜索框中寻找轮廓框(距离上一定位框小于对角线一半的优先级高于搜索框)
    if (search_rect_count == 0) {
        for (int i = 0; i < contours.size(); i++)
        {

            boundRect[i] = boundingRect(contours[i]);//边缘矩形赋值给定义的矩形数组元素

            if (boundRect[i].tl().y < (50 * 1.0 / shrink) || boundRect[i].tl().x < (50 * 1.0 / shrink) || boundRect[i].br().x>(1700 * 1.0 / shrink) || boundRect[i].br().y>(900 * 1.0 / shrink)) {//边缘矩形
                //boundRect[i] = Rect(pre_Rect_x, pre_Rect_y, 1, 1);//边缘矩形 加进去上一个位置点
                continue;
            }

            //在上一个矩形标注框的3*3的区域搜索矩形
            int search_lt_x = pre_Rect.tl().x - 1.0 * pre_Rect_width;//左上角点的x值
            int search_lt_y = pre_Rect.tl().y - 1.0 * pre_Rect_height;//左上角点的y值
            int search_br_x = pre_Rect.br().x + 1.0 * pre_Rect_width;//右下角点的x值
            int search_br_y = pre_Rect.br().y + 1.0 * pre_Rect_height;//右下角的y值
            Point search_lt = Point(search_lt_x, search_lt_y);//左上角点
            Point search_br = Point(search_br_x, search_br_y);//右下角点
            Rect search_Rect = Rect(search_lt, search_br);//搜索矩形

            //判断矩形相交或搜索矩形包含轮廓矩形 条件1-4满足任意一个即可判断其相交或包含
            bool limit1 = (boundRect[i].tl().x > search_lt_x&&boundRect[i].tl().x < search_br_x) && (boundRect[i].tl().y > search_lt_y&&boundRect[i].tl().y < search_br_y); //该矩形左上角在搜索区域内
            //用轮廓矩形左上角的y右下角的x值代替右上角的值
            int boundRect_rt_x = boundRect[i].br().x;
            int boundRect_rt_y = boundRect[i].tl().y;
            bool limit2 = (boundRect_rt_x > search_lt_x&&boundRect_rt_x < search_br_x) && (boundRect_rt_y > search_lt_y&&boundRect_rt_y < search_br_y);//该矩形右上角在搜索区域内
            bool limit3 = (boundRect[i].br().x > search_lt_x&&boundRect[i].br().x < search_br_x) && (boundRect[i].br().y > search_lt_y&&boundRect[i].br().y < search_br_y); //该矩形右下角在搜索区域内
            //用轮廓的矩形左上角的x右下角的y值代替左下角的值
            int boundRect_bl_x = boundRect[i].tl().x;
            int boundRect_bl_y = boundRect[i].br().y;
            bool limit4 = (boundRect_bl_x > search_lt_x&&boundRect_bl_x < search_br_x) && (boundRect_bl_y > search_lt_y&&boundRect_bl_y < search_br_y);//该矩形右上角在搜索区域内

            if ((limit1 || limit2 || limit3 || limit4)) {
                if (boundRect[i].width < 3 * boundRect[i].height&&boundRect[i].height < 3 * boundRect[i].width) {//去除长条的矩形
                    search_area_boundRect[search_rect_count++] = boundRect[i];
                    rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);
                }
            }
            rectangle(result, search_Rect, Scalar(255, 0, 0), 2);//在result上绘制正外接搜索矩形框 
            //rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形

        }
    }

    ////如果还没找到扩大搜索框为5*5
    //if (search_rect_count == 0) {
    //    for (int i = 0; i < contours.size(); i++)
    //    {
    //        boundRect[i] = boundingRect(contours[i]);//边缘矩形赋值给定义的矩形数组元素

    //        if (boundRect[i].tl().y < (50 * 1.0 / shrink) || boundRect[i].tl().x < (50 * 1.0 / shrink) || boundRect[i].br().x>(1700 * 1.0 / shrink) || boundRect[i].br().y>(900 * 1.0 / shrink)) {//边缘矩形
    //            //boundRect[i] = Rect(pre_Rect_x, pre_Rect_y, 1, 1);//边缘矩形 加进去上一个位置点
    //            continue;
    //        }

    //        //在上一个矩形标注框的3*3的区域搜索矩形
    //        int search_lt_x = pre_Rect.tl().x - 1.2 * pre_Rect_width;//左上角点的x值
    //        int search_lt_y = pre_Rect.tl().y - 1.2 * pre_Rect_height;//左上角点的y值
    //        int search_br_x = pre_Rect.br().x + 1.2 * pre_Rect_width;//右下角点的x值
    //        int search_br_y = pre_Rect.br().y + 1.2 * pre_Rect_height;//右下角的y值
    //        Point search_lt = Point(search_lt_x, search_lt_y);//左上角点
    //        Point search_br = Point(search_br_x, search_br_y);//右下角点
    //        Rect search_Rect = Rect(search_lt, search_br);//搜索矩形

    //        //判断矩形相交或搜索矩形包含轮廓矩形 条件1-4满足任意一个即可判断其相交或包含
    //        bool limit1 = (boundRect[i].tl().x > search_lt_x&&boundRect[i].tl().x < search_br_x) && (boundRect[i].tl().y > search_lt_y&&boundRect[i].tl().y < search_br_y); //该矩形左上角在搜索区域内
    //        //用轮廓矩形左上角的y右下角的x值代替右上角的值
    //        int boundRect_rt_x = boundRect[i].br().x;
    //        int boundRect_rt_y = boundRect[i].tl().y;
    //        bool limit2 = (boundRect_rt_x > search_lt_x&&boundRect_rt_x < search_br_x) && (boundRect_rt_y > search_lt_y&&boundRect_rt_y < search_br_y);//该矩形右上角在搜索区域内
    //        bool limit3 = (boundRect[i].br().x > search_lt_x&&boundRect[i].br().x < search_br_x) && (boundRect[i].br().y > search_lt_y&&boundRect[i].br().y < search_br_y); //该矩形右下角在搜索区域内
    //        //用轮廓的矩形左上角的x右下角的y值代替左下角的值
    //        int boundRect_bl_x = boundRect[i].tl().x;
    //        int boundRect_bl_y = boundRect[i].br().y;
    //        bool limit4 = (boundRect_bl_x > search_lt_x&&boundRect_bl_x < search_br_x) && (boundRect_bl_y > search_lt_y&&boundRect_bl_y < search_br_y);//该矩形右上角在搜索区域内

    //        if ((limit1 || limit2 || limit3 || limit4)) {
    //            if (boundRect[i].width < 3 * boundRect[i].height&&boundRect[i].height < 3 * boundRect[i].width) {//去除长条的矩形
    //                search_area_boundRect[search_rect_count++] = boundRect[i];
    //                rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);
    //            }
    //        }
    //        rectangle(result, search_Rect, Scalar(255, 0, 0), 2);//在result上绘制正外接搜索矩形框 
    //        //rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形
    //    }
    //}



    //在的轮廓矩形search_area_boundRect中寻找最大面积矩形
    Rect max_Rect = Rect(Point(0, 0), Point(0, 0));

    double max_area = -1;//防止面积为0的矩形检测不出
    for (int i = 0; i < search_rect_count; i++) {
        if (search_area_boundRect[i].area() > max_area) {
            max_Rect = search_area_boundRect[i];//找出最大矩形
            max_area = search_area_boundRect[i].area();
        }
    }


    //vector<Rect> select_boundRect(contours.size());//在搜索区域内的轮廓矩形中挑选出离最大矩形较近的矩形 100
    //int select_boundRect_count = 0;
    //int maxRect_x = max_Rect.tl().x + max_Rect.height / 2, maxRect_y = max_Rect.tl().y + max_Rect.width / 2;//中心点(最大矩形的重心)
    //for (int i = 0; i < search_rect_count; i++) {
    //    int distance;//两矩形中心点求距离
    //    int x = (search_area_boundRect[i].tl().x + search_area_boundRect[i].br().x) / 2, y = (search_area_boundRect[i].tl().y + search_area_boundRect[i].br().y) / 2;//遍历矩形的重心
    //    distance = (maxRect_x - x)*(maxRect_x - x) + (maxRect_y - y)*(maxRect_y - y);
    //    //if (distance <= 10000 * 1.0 / (shrink*shrink)) {
    //    select_boundRect[select_boundRect_count++] = search_area_boundRect[i];//挑出到最大矩形重心距离小于100/16的矩形
    ////}
    //}
    //int min_x = 2000, min_y = 2000, max_x = 0, max_y = 0;//找到左上角和右下角的坐标
    //for (int i = 0; i < select_boundRect_count; i++) {
    //    if (select_boundRect[i].tl().x < min_x) {
    //        min_x = select_boundRect[i].tl().x;//最小x值
    //    }if (select_boundRect[i].tl().y < min_y) {
    //        min_y = select_boundRect[i].tl().y;//最小y值
    //    }
    //    if (select_boundRect[i].br().x > max_x) {
    //        max_x = select_boundRect[i].br().x;
    //    }
    //    if (select_boundRect[i].br().y > max_y) {
    //        max_y = select_boundRect[i].br().y;
    //    }
    //    //rectangle(result, select_boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形 
    //}
    ////最大矩形合并周围矩形
    //Rect draw_Rect = Rect(Point(min_x, min_y), Point(max_x, max_y));

    //if (min_x == 2000 || min_y == 2000 || max_x == 0 || max_y == 0) {
    //    draw_Rect = pre_Rect;//物体静止时 将之前的矩形赋给当前矩形
    //}

    Rect draw_Rect;
    draw_Rect = max_Rect;
    double centers_distance = getDistance(getCenterPoint(draw_Rect), getCenterPoint(pre_Rect));//这一帧框和上一帧框两中心点间的距离
    double diagonal = getDistance(max_Rect.tl(), max_Rect.br());//当前框的对角线的距离

    if (max_Rect.area() == 0 || centers_distance > diagonal) {
        draw_Rect = pre_Rect;
    }
    //防止孤立点出现或者框过小
    if (draw_Rect.width < 40) {
        draw_Rect = Rect(Point(draw_Rect.tl().x - (40 - draw_Rect.width) / 2, draw_Rect.tl().y), Point(draw_Rect.br().x + (40 - draw_Rect.width) / 2, draw_Rect.br().y));
    }
    if (draw_Rect.height < 20) {
        draw_Rect = Rect(Point(draw_Rect.tl().x, draw_Rect.tl().y - (20 - draw_Rect.height) / 2), Point(draw_Rect.br().x, draw_Rect.br().y + (draw_Rect.height) / 2));
    }


    pre_Rect = draw_Rect;
    rectangle(result, draw_Rect, Scalar(0, 0, 255), 2);//在result上绘制正外接矩形  

    return result;//返回result  
}
//求矩形框的中心点
Point getCenterPoint(Rect rect) {
    Point cpt;
    cpt.x = rect.x + cvRound(rect.width / 2.0);//cvRound四舍五入
    cpt.y = rect.y + cvRound(rect.height / 2.0);
    return cpt;
}
//求两点之间的距离
double getDistance(Point p1, Point p2) {
    return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}

void onMouse(int event, int x, int y, int, void *) {
    if (event == CV_EVENT_LBUTTONDOWN) {
        pre_Rect.x = x;
        pre_Rect.y = y;
    }
    else if (event == CV_EVENT_LBUTTONUP) {
        pre_Rect.width = x - pre_Rect.x;
        pre_Rect.height = y - pre_Rect.y;
    }
}

缺点:

1.不能够达到实时检测 在背景简单时每秒检测大概20-30帧 更简单背景时也能达到30帧以上,但背景复杂时每秒仅为3-4帧

2.视频图片前后帧的拼接结果好坏直接影响最终的无人机定位效果

3.如果跟踪框丢失 再次找回具有偶然性 只有当目标再次落入搜索框内才可能再次进行跟踪

猜你喜欢

转载自www.cnblogs.com/henuLiGang/p/10281256.html