图像处理 跟踪方法_数字图像处理轮廓跟踪 - CSDN
  • openCV光流法追踪运动物体

    openCV光流法追踪运动物体

    email:chentravelling@163.com

    一、光流简介

    摘自:zouxy09

            光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

    研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

           那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。

            那怎么知道第t+1帧的时候A点的位置呢? 这就存在很多的光流计算方法了。

           1981年,Horn和Schunck创造性地将二维速度场与灰度相联系,引入光流约束方程,得到光流计算的基本算法。人们基于不同的理论基础提出各种光流计算方法,算法性能各有不同。Barron等人对多种光流计算技术进行了总结,按照理论基础与数学方法的区别把它们分成四种:基于梯度的方法、基于匹配的方法、基于能量的方法、基于相位的方法。近年来神经动力学方法也颇受学者重视。

    OpenCV中实现了不少的光流算法。

    可参考:http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/video/doc/motion_analysis_and_object_tracking.html

    1)calcOpticalFlowPyrLK

    通过金字塔Lucas-Kanade 光流方法计算某些点集的光流(稀疏光流)。理解的话,可以参考这篇论文:”Pyramidal Implementation of the Lucas Kanade Feature TrackerDescription of the algorithm”

    2)calcOpticalFlowFarneback

    用Gunnar Farneback 的算法计算稠密光流(即图像上所有像素点的光流都计算出来)。它的相关论文是:"Two-Frame Motion Estimation Based on PolynomialExpansion"

    3)CalcOpticalFlowBM

    通过块匹配的方法来计算光流。

    4)CalcOpticalFlowHS

    用Horn-Schunck 的算法计算稠密光流。相关论文好像是这篇:”Determining Optical Flow”

    5)calcOpticalFlowSF

    这一个是2012年欧洲视觉会议的一篇文章的实现:"SimpleFlow: A Non-iterative, Sublinear Optical FlowAlgorithm",工程网站是:http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/  在OpenCV新版本中有引入。

           稠密光流需要使用某种插值方法在比较容易跟踪的像素之间进行插值以解决那些运动不明确的像素,所以它的计算开销是相当大的。而对于稀疏光流来说,在他计算时需要在被跟踪之前指定一组点(容易跟踪的点,例如角点),因此在使用LK方法之前我们需要配合使用cvGoodFeatureToTrack()来寻找角点,然后利用金字塔LK光流算法,对运动进行跟踪。

    二、代码

    #include <opencv2\opencv.hpp>
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    const int MAX_CORNERS = 100;
    
    int main()
    {
    	IplImage* preImage = cvLoadImage("image133.pgm",CV_LOAD_IMAGE_GRAYSCALE);
    	IplImage* curImage = cvLoadImage("image134.pgm",CV_LOAD_IMAGE_GRAYSCALE);
    	IplImage* curImage_ = cvLoadImage("image134.pgm");
    	CvPoint2D32f* preFeatures = new CvPoint2D32f[ MAX_CORNERS ];//前一帧中特征点坐标(通过cvGoodFeaturesToTrack获得)  
    	CvPoint2D32f* curFeatures = new CvPoint2D32f[ MAX_CORNERS ];//在当前帧中的特征点坐标(通过光流法获得)
    	double qlevel; //特征检测的指标  
    	double minDist;//特征点之间最小容忍距离  
    	vector<uchar> status; //特征点被成功跟踪的标志  
    	vector<float> err; //跟踪时的特征点小区域误差和 
    	CvSize      img_sz    = cvGetSize(preImage);  
    	IplImage* eig_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );//缓冲区  
    	IplImage* tmp_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );
    	int num = MAX_CORNERS;
    	cvGoodFeaturesToTrack(//获取特征点
    		preImage,
    		eig_image,
    		tmp_image,
    		preFeatures,
    		&num,
    		0.01,  
    		5.0,  
    		0,  
    		3,  
    		0,  
    		0.04  
    		);
    	CvSize pyr_sz = cvSize( curImage->width+8, curImage->height/3 );  
    	IplImage* pyrA = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );  
    	IplImage* pyrB = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );  
    	
    	char features_found[ MAX_CORNERS ];  
    	float feature_errors[ MAX_CORNERS ];  
    
    	
    	cvCalcOpticalFlowPyrLK(//计算光流
    		preImage,
    		curImage,
    		pyrA,
    		pyrB,
    		preFeatures,
    		curFeatures,
    		MAX_CORNERS,
    		cvSize(10,10),
    		5,  
    		features_found,  
    		feature_errors,  
    		cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 ),  
    		0  
    		);
    
    	
    	for(int i=0;i<MAX_CORNERS;i++)//画线
    	{
    	cvLine(
    		curImage_,
    		Point(preFeatures[i].x,preFeatures[i].y),
    		Point(curFeatures[i].x,curFeatures[i].y),
    		CV_RGB(255,0,0),
    		4,
    		CV_AA,
    		0);
    	}
    	
    	cvShowImage("outPutImage",curImage_);
    	//cvSaveImage("outPutImage.pgm",curImage);
    	waitKey(0);
    	return 0;
    }

    最终结果:



    展开全文
  • 图像处理入门:物体跟踪(一)

    千次阅读 2018-11-13 10:44:26
    该方法是最简单得物体跟踪方法,即利用掩膜和位运算的方法来追踪特定颜色的物体. 核心方法: def object_tacking(frame): hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) # 设置颜色阈值 lower = np.array([110...

    该方法是最简单得物体跟踪方法,即利用掩膜和位运算的方法来追踪特定颜色的物体.

    核心方法:

    def object_tacking(frame):
        hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
        # 设置颜色阈值
        lower = np.array([110, 50, 50])
        upper = np.array([130, 255, 255])
        # 掩膜
        mask=cv2.inRange(hsv,lower,upper)
        # 位运算
        res=cv2.bitwise_and(frame,frame,mask=mask)
    
        cv2.imshow('frame', frame)
        cv2.imshow('mask', mask)
        cv2.imshow('res', res)
        if cv2.waitKey(5)&0xFF==27:
            cv2.destroyAllWindows()

     

    展开全文
  • 形态学图像处理之边界提取与跟踪

    千次阅读 2019-08-11 22:07:58
    要在二值图像中提取物体的边界,容易想到的一个方法是将所有物体内部的点删除(置为背景色)。具体地说,可以逐行扫描图像,如果发现一个黑点的8个邻域都是黑点,则该点为内部点,在目标图 像中将它删除。实际上这...

    边界提取

            要在二值图像中提取物体的边界,容易想到的一个方法是将所有物体内部的点删除(置为背景色)。具体地说,可以逐行扫描图像,如果发现一个黑点的8个邻域都是黑点,则该点为内部点,在目标图 像中将它删除。实际上这相当于采用一个3*3的结构元素对原图进行腐蚀,使得只有那些8个邻域都有黑点的内部点被保留,再用原图像减去腐蚀后的图像,恰好删除了这些内部点,留下了边界像素。这过程如下图所示。
    在这里插入图片描述

    示例演示

            利用OpenCV实现上面边界提取的功能。

    #include<opencv2/opencv.hpp>
    using namespace cv;
    
    int main(int argc, char *argv[])
    {
       Mat originimage = imread("E:/TestData/head_portrait.bmp");
       Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
       imshow("OriginImage", originimage);
       Mat erodeimage;
       cv::erode(originimage, erodeimage, element);
       imshow("ErodeImage", erodeimage);
    
       Mat output = originimage -  erodeimage;
       imshow("Output", output);
    
    
        waitKey(0);
        return 0;
    
    }
    

    运行结果

    在这里插入图片描述

    边界跟踪

            为了依次记录边界上的每个像素,边界跟踪首先按照某种扫描规则找到目标物体边界上的一个像素,然后就以该像素为起始点,根据某种顺序(如顺时针或逆时针)依次找出物体边界上的其余像素,直到又回到起始点,完成整条边界的跟踪。
    例如,我们可以按照从左到右、从上到下的顺序扫描图像,这样首先会找到目标物体最左上方的边界点P0.显然,这个点的左侧及上侧都不可能存在边界点(否则左侧或上侧的边界点就会称为第一个被扫描到的边界点),因此不妨从左下方逆时针开始探查,如左下方的点是黑点,直接跟踪至此边界点,否则探查方向逆时针旋转45度,直至找到第一个黑点为止,跟踪至此边界点。找到边界点后,在当前探查方向的基础上顺时针回转90度,继续用上述方法搜索下一个边界点,知道探查又回到初始的边界点P0,则完成整条边界的跟踪。

    示例演示

            在一幅图像中,实现跟踪多个边界的功能。对于带孔洞的物体也可以跟踪至其孔洞的轮廓。

    #include<opencv2/opencv.hpp>
    using namespace cv;
    
    //only process binary image
    //black is boundary
    std::vector<std::vector<cv::Point>> TraceBoundary(Mat &image)
    {
        std::vector<std::vector<Point>> boundaryset;
        Point start, current, next; // start point and current point
        //search dirction array
        int direction[8][2] ={{-1, 1}, //left-down
                              {0, 1}, // down
                              {1, 1}, //right-down
                              {1, 0}, //right
                              {1, -1}, //right-up
                              {0, -1}, //up
                              {-1, -1}, //left-up
                              {-1, 0}  // left
                             };
        int begindirection = 0, currentdirection = 0;
        bool atstart = false, findboundary = false;
    
        for(int i = 0; i < image.rows; i++)
        {
            for(int j = 0; j < image.cols; j++)
            {
                if(image.at<uchar>(i, j) == 0) //find start point
                {
                    start.x = j;
                    start.y = i;
                    current = start;
                    atstart = true;
                    findboundary =  true;
                    std::vector<Point> points;
                    points.push_back(current);
                    std::cout << "Start: " << j << " " << i << std::endl;
                    while((current.x != start.x) || (current.y != start.y) || atstart)
                    {
                        atstart = false;
    
                        //search next point
                        next.x = current.x + direction[currentdirection][0];
                        next.y = current.y + direction[currentdirection][1];
                        int searchtimes = 1;
                        while(next.x < 0 || next.x >= image.cols || next.y < 0 || next.y >= image.rows || image.at<uchar>(next) == 255)
                        {
                            currentdirection++; //rotate 45 degrees counterclockwise
                            currentdirection %= 8;
                            next.x = current.x + direction[currentdirection][0];
                            next.y = current.y + direction[currentdirection][1];
                            //there are no boundary points in 8 domains, which means they are isolated points
                            if(++searchtimes >= 8)
                                break;
                        }
                        if(image.at<uchar>(next) == 0) // find next point
                        {
                            std::cout << "Next: " << next.x << " " << next.y << std::endl;
                            points.push_back(next);
                            current = next;
                            currentdirection -= 2;
                            if(currentdirection < 0)
                                currentdirection += 8;
    
                        }
                        else // not find next point
                        {
                            findboundary = false;
                            break;
                        }
                    }
                    if(findboundary)
                    {
                        boundaryset.push_back(points);
                        for(auto &p : points)
                        {
                            image.at<uchar>(p) = 255;
                        }
                    }
                } // find boundary one time
            } // for j
        } // for i
        return boundaryset;
    }
    
    int main(int argc, char *argv[])
    {
       Mat originimage = imread("E:/TestData/head_boundary.bmp");
       imshow("OriginImage", originimage);
    
       Mat image;
       cvtColor(originimage, image, CV_BGR2GRAY);
       std::vector<std::vector<Point>> boundaryset = TraceBoundary(image);
    
       //show result
       Mat result;
       originimage.copyTo(result);
       for(auto &points : boundaryset)
       {
           for(auto &p : points)
           {
                result.at<Vec3b>(p)[0]= 0;
                result.at<Vec3b>(p)[0]= 0;
                result.at<Vec3b>(p)[1]= 255;
           }
       }
       imshow("Output", result);
    
    
        waitKey(0);
        return 0;
    
    }
    

    运行结果

    在这里插入图片描述

    展开全文
  • 本来是先学跟踪视频中运动目标,看《opencv2 计算机视觉编程手册》走错了路,就先学了这块。废话不多说,代码先贴上来,已运行成功。、 #include "stdafx.h" #include #include #include #include #include...

    本来是先学跟踪视频中运动目标,看《opencv2 计算机视觉编程手册》走错了路,就先学了这块。废话不多说,代码先贴上来,已运行成功。、

    #include "stdafx.h"
    
    
    #include <opencv2/video/video.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/core/core.hpp>
     
    #include <iostream>
    #include <cstdio>
     
    
    using namespace std;
    using namespace cv;
     
    
    void tracking(Mat &frame, Mat &output);
     
    bool addNewPoints();
     
    bool acceptTrackedPoint(int i);
     
    
    string window_name = "optical flow tracking";
     
    Mat gray;        // 当前图片
     
    Mat gray_prev;        // 预测图片
     
    vector<Point2f> points[2];        // point0为特征点的原来位置,point1为特征点的新位置
     
    vector<Point2f> initial;        // 初始化跟踪点的位置
     
    vector<Point2f> features;        // 检测的特征
     
    int maxCount = 500;        // 检测的最大特征数
     
    double qLevel = 0.01;        // 特征检测的等级
     
    double minDist = 10.0;        // 两特征点之间的最小距离
     
    vector<uchar> status;        // 跟踪特征的状态,特征的流发现为1,否则为0
     
    vector<float> err;
     
    
    int main()
     
    {
     
            Mat frame;
     
            Mat result;
     
    
    //         CvCapture* capture = cvCaptureFromCAM( -1 );        // 摄像头读取文件开关
     
            VideoCapture capture("C:\\Users\\Administrator\\Desktop\\数据\\chuli\\chuli\\car.avi");
     
    
            if(capture.isOpened()/*capture*/)        // 摄像头读取文件开关
     
            {
     
                    while(true)
     
                    {
     
    //                         frame = cvQueryFrame( capture );        // 摄像头读取文件开关
     
                            capture >> frame;
     
    
                            if(!frame.empty())
     
                            { 
                                    tracking(frame, result);
     
                            }
     
                            else
     
                            { 
                                    printf(" --(!) No captured frame -- Break!");
     
                                    break;
     
                            }
     
    
                            int c = waitKey(100);
     
                            if( (char)c == 27 )
     
                            {
     
                                    break; 
                            } 
                    }
     
            }
     
            return 0;
     
    }
     
    
    //
     
    // function: tracking
     
    // brief: 跟踪
     
    // parameter: frame        输入的视频帧
     
    //                          output 有跟踪结果的视频帧
     
    // return: void
     
    //
     
    void tracking(Mat &frame, Mat &output)
     
    {
     
            cvtColor(frame, gray, CV_BGR2GRAY);
     
            frame.copyTo(output);
     
            // 添加特征点
     
            if (addNewPoints())
     
            {
     
                    goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
     
                    points[0].insert(points[0].end(), features.begin(), features.end());
     
                    initial.insert(initial.end(), features.begin(), features.end());
     
            }
     
    
            if (gray_prev.empty())
     
            {
     
                    gray.copyTo(gray_prev);
     
            }
     
            // l-k光流法运动估计
     
            calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
     
            // 去掉一些不好的特征点
     
            int k = 0;
     
            for (size_t i=0; i<points[1].size(); i++)
     
            {
     
                    if (acceptTrackedPoint(i))
     
                    {
     
                            initial[k] = initial[i];
     
                            points[1][k++] = points[1][i];
     
                    }
     
            }
     
            points[1].resize(k);
     
            initial.resize(k);
     
            // 显示特征点和运动轨迹
     
            for (size_t i=0; i<points[1].size(); i++)
     
            {
     
                    line(output, initial[i], points[1][i], Scalar(0, 0, 255));
     
                    circle(output, points[1][i], 3, Scalar(255, 0, 0), -1);
     
            }
     
    
            // 把当前跟踪结果作为下一此参考
     
            swap(points[1], points[0]);
     
            swap(gray_prev, gray);
     
    
            imshow(window_name, output);
     
    }
     
    
    //
     
    // function: addNewPoints
     
    // brief: 检测新点是否应该被添加
     
    // parameter:
     
    // return: 是否被添加标志
     
    //
     
    bool addNewPoints()
     
    {
     
            return points[0].size() <= 10;
     
    }
     
    
    //
     
    // function: acceptTrackedPoint
     
    // brief: 决定哪些跟踪点被接受
     
    // parameter:
     
    // return:
     
    //
     
    bool acceptTrackedPoint(int i)
     
    {
     
            return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
     
    }

    此方法中处理视频帧用的是函数,其实并不是很好,使用处理帧类会更加灵活。但自己并没有调试出来,一直报错,还需努力。



    展开全文
  • 图像处理之目标跟踪 简单分类 罗列    目标跟踪发展十分快,门类非常多,这里简单将其罗列,主要参考:   HakaseH Tracking Benchmark for Correlation Filters  另外推荐:  foolwood Benchmark...
  • 图像处理面试方法和前景

    千次阅读 2016-05-29 16:15:40
    最近版上有不少人在讨论图像处理的就业方向,似乎大部分都持悲观的态度。我想结合我今年找工作的经验谈谈我的看法。就我看来,个人觉得图像处理的就业还是不错的。首先可以把图像看成二维、三维或者更高维的信号,从...
  • matlab图像处理之二值图像内外边界跟踪 注:原文链接:http://www.cnblogs.com/tiandsp/archive/2013/04/26/3045747.html  目标内边界的像素全都在目标里面,目标外边界的像素全都不在目标上,是包围着目标的。 二...
  • 边界跟踪:内边界跟踪算法解释 边界跟踪是基于边缘的分割常用方法之一,用于区域已分出(二值或已标注),但边界未知的情况。分为内边界与外边界。内边界为区域的一个子集,外边界不是区域的一个子集。 内边界...
  • 图像处理基本算法 链码 边界跟踪

    千次阅读 2016-11-18 17:39:16
    链码在图像提取的后期即模式识别是一个很重要的特征,比如进行数字识别或者文字识别都会用到链码的特征,而链码的提取则可以借助于边界跟踪算法获取边界序列,注意是边界序列而不是边界,边界很容易获取,但是要想把...
  • 图像处理入门教程

    万次阅读 多人点赞 2018-04-20 19:00:46
    最近有人问我图像处理怎么研究,怎么入门,怎么应用,我竟一时语塞。仔细想想,自己也搞了两年图像方面的研究,做个两个创新项目,发过两篇论文,也算是有点心得,于是总结总结和大家分享,希望能对大家有所帮助。在...
  • 常用传统图像处理方法总结

    千次阅读 2019-02-19 14:11:07
    1. 边缘提取 1.1 微分算子检测边缘 一阶算子:一阶导数的极大值点 二阶算子:二阶导数的过零点 一阶算子: Prewitt算子 , sobel算子(给...最常用的边缘检测方法。能够噪声抑制,边缘增强,边缘定位。 算法分为三步...
  • 图像分割方法总结
  • 图像处理入门必看

    万次阅读 多人点赞 2017-11-27 22:36:25
    (原MyBlog)前要说明这段时间在网上找资料学习图像处理的相关知识,在网上看到这篇写得相当不错的文章,在大牛允许转载的情况下,特搬家至此,方便更多的初学者能够看到。正文开始最近有人问我图像处理怎么研究,怎么...
  • 图像处理分类、一般流程与算法

    千次阅读 2019-08-10 09:15:50
    常用的图像处理算法:数字图像处理基础、遥感数字图像处理、机器视觉、计算机视觉 图像处理程序:C++ OpenCV、Matlab与图像处理 1. 数字图像处理-概述 其实,造成“不可能图形”(三角形的三个角都是90°)的并...
  • 图像处理(image processing),用计算机对图像进行分析,以达到所需结果的技术。又称影像处理。图像处理一般指数字图像处理。数字图像是指用工业相机、摄像机、扫描仪等设备经过拍摄得到的一个大的二维数组,该数组的...
  • 在我的理解里,要实现计算机视觉必须有图像处理的帮助,而图像处理倚仗与模式识别的有效运用,而模式识别是人工智能领域的一个重要分支,人工智能与机器学习密不可分。纵观一切关系,发现计算机视觉的应用服务于机器...
  • 浅谈安防监控中视频图像处理技术

    千次阅读 2019-08-16 08:48:45
    随着计算机软件、硬件技术的日新月异的发展和普及,人类已经进入一个高速发展的信息化时代,人类大概有80%的信息来自图像,科学研究、技术应用中图像处理技术越来越成为不可缺少的手段。安防行业已经进入一个崭新的...
  • 形态学图像处理

    万次阅读 多人点赞 2016-12-31 16:17:01
    形态学,即数学形态学(mathematical Morphology),是图像处理中应用最为广泛的技术之一,主要用于从图像中提取对表达和描绘区域形状有意义的图像分量,使后续的识别工作能够抓住目标对象最为本质〈最具区分能力-...
  • 图像处理经典文献

    千次阅读 2018-01-29 10:43:26
    我们所说的图像处理实际上就是数字图像处理,是把真实世界中的连续三维随机信号投影到传感器的二维平面上,采样并量化后得到二维矩阵。数字图像处理就是二维矩阵的处理,而从二维图像中恢复出三维场景就是计算机视觉...
  • 计算机视觉和图像处理框架

    千次阅读 2016-09-02 10:13:43
    计算机视觉和图像处理框架一、概述图像处理即传感器将图像信号转换为数字信号,再利用计算机对其进行加工处理的过程。其涉及到的方法主要有图像变换、图像编码、图像去噪、图像增强、图像恢复、图像分割、特征提取、...
1 2 3 4 5 ... 20
收藏数 52,967
精华内容 21,186
关键字:

图像处理 跟踪方法