zoukankan      html  css  js  c++  java
  • opencv2对读书笔记——使用均值漂移算法查找物体

    一些小概念


    1.反投影直方图的结果是一个概率映射,体现了已知图像内容出如今图像中特定位置的概率。

    2.概率映射能够找到最初的位置,从最初的位置開始而且迭代移动,便能够找到精确的位置,这就是均值漂移算法做的事情。

    3.均值漂移算法是以迭代的方式锁定函数的局部最大值的。


    关于均值漂移算法的过程(opencv)


    事实上均值漂移算法就是寻找提前定义寻找区域中数据点的重心,或者说加权平均值。将寻找区域中心移动到数据点的重心处,并反复这个过程直到寻找区域重心收敛到一个稳定点。

    OpenCV中定义了两种终止条件:迭代最大次数以及窗体重心的位移值(低于该值即觉得算法收敛)。

    在OpenCV中实现这个过程的是meanshift函数,其源码例如以下:


    #include "_cv.h"
    
    CV_IMPL int
    cvMeanShift( const void* imgProb, CvRect windowIn,
                 CvTermCriteria criteria, CvConnectedComp* comp )
    {
        //CvMoments用来计算矩形的重心,面积等形状特征
        CvMoments moments;
        int    i = 0, eps;
        CvMat  stub, *mat = (CvMat*)imgProb;
        CvMat  cur_win;
        CvRect cur_rect = windowIn;
    
        CV_FUNCNAME( "cvMeanShift" );
    
        //初始化跟踪窗体
        if( comp )
            comp->rect = windowIn;
    
        //把0阶矩和1阶矩先初始化置零
        moments.m00 = moments.m10 = moments.m01 = 0;
    
        __BEGIN__;
    
        CV_CALL( mat = cvGetMat( mat, &stub ));
    
        //各种输入变量不符合要求时显示错误信息
        if( CV_MAT_CN( mat->type ) > 1 )
            CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
        if( windowIn.height <= 0 || windowIn.width <= 0 )
            CV_ERROR( CV_StsBadArg, "Input window has non-positive sizes" );
        if( windowIn.x < 0 || windowIn.x + windowIn.width > mat->cols ||
            windowIn.y < 0 || windowIn.y + windowIn.height > mat->rows )
            CV_ERROR( CV_StsBadArg, "Initial window is not inside the image ROI" );
    
        //迭代的标准,精度=1.0,迭代次数=100
        CV_CALL( criteria = cvCheckTermCriteria( criteria, 1., 100 ));
    
        //精度eps=1
        eps = cvRound( criteria.epsilon * criteria.epsilon );
    
        //最大循环次数=最大迭代次数criteria.max_iter=100
        for( i = 0; i < criteria.max_iter; i++ )
        {
            int dx, dy, nx, ny;
            double inv_m00;
    
            //选取搜索区域,对该矩形区域计算它的0,1阶矩
            CV_CALL( cvGetSubRect( mat, &cur_win, cur_rect )); 
            CV_CALL( cvMoments( &cur_win, &moments ));
    
            /* Calculating center of mass */
            if( fabs(moments.m00) < DBL_EPSILON )
                break;
    
            //搜索区域的质量m00
            inv_m00 = moments.inv_sqrt_m00*moments.inv_sqrt_m00;
            //搜索区域的水平重心偏移dx
            dx = cvRound( moments.m10 * inv_m00 - windowIn.width*0.5 );
            //搜索区域的垂直重心偏移dy
            dy = cvRound( moments.m01 * inv_m00 - windowIn.height*0.5 );
    
            //搜索区域的重心坐标(nx,ny)
            nx = cur_rect.x + dx;
            ny = cur_rect.y + dy;
    
            //跟踪目标处于图像边缘时进行一些对应的处理
            if( nx < 0 )
                nx = 0;
            else if( nx + cur_rect.width > mat->cols )
                nx = mat->cols - cur_rect.width;
    
            if( ny < 0 )
                ny = 0;
            else if( ny + cur_rect.height > mat->rows )
                ny = mat->rows - cur_rect.height;
    
            dx = nx - cur_rect.x;
            dy = ny - cur_rect.y;
            cur_rect.x = nx;
            cur_rect.y = ny;
    
            /* Check for coverage centers mass & window */
            //精度达到要求时就可以退出循环
            if( dx*dx + dy*dy < eps )
                break;
        }
    
        __END__;
    
        //对meanshift函数的返回值赋值
        if( comp )
        {
            comp->rect = cur_rect;
            comp->area = (float)moments.m00;
        }
    
        return i;
    }

    在里面我们能够非常easy的看出迭代过程

    对这个算法想细致研究的同学能够參考一下Dorin Comaniciu 等人2002年写的:

    《Mean Shift:A Robust Approach Toward Feature Space Analysis》


    实际样例


    样例代码


    #include <opencv2corecore.hpp>
    #include <opencv2highguihighgui.hpp>
    #include <opencv2imgprocimgproc.hpp>
    #include <opencv2video	racking.hpp>
    
    #include <iostream>
    #include <vector>
    using namespace std;
    
    #include "objectFinder.h"
    #include "colorhistogram.h"
    
    int main()
    {
    	//读取參考图像
    	cv::Mat image= cv::imread("../3.jpg");
    	if (!image.data)
    		return 0; 
    
    	//定义查找物体
    	cv::Mat imageROI= image(cv::Rect(85,200,64,64));
    	cv::rectangle(image, cv::Rect(85,200,64,64),cv::Scalar(0,0,255));
    
    	//显示參考图像
    	cv::namedWindow("第一张图片,标记篮球位置");
    	cv::imshow("第一张图片,标记篮球位置",image);
    
    	//获得色度直方图
    	ColorHistogram hc;
    	cv::MatND colorhist= hc.getHueHistogram(imageROI);
    
    	//读入目标图像
    	image= cv::imread("../4.jpg");
    
    	//显示目标图像
    	cv::namedWindow("第二张图片");
    	cv::imshow("第二张图片",image);
    
    	//将RGB图像图像转换为HSV图像
    	cv::Mat hsv;
    	cv::cvtColor(image, hsv, CV_BGR2HSV);
    
    	//分离图像通道
    	vector<cv::Mat> v;
    	cv::split(hsv,v);
    
    	//消除饱和度较低的像素点
    	int minSat=65;
    	cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY);
    	cv::namedWindow("第二张图片消除饱和度较低的像素点");
    	cv::imshow("第二张图片消除饱和度较低的像素点",v[1]);
    
    	//进行直方图反投影
    	ObjectFinder finder;
    	finder.setHistogram(colorhist);
    	finder.setThreshold(0.3f);
    	int ch[1]={0};
    	cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1);
    
    	cv::namedWindow("第二张图片进行直方图反投影");
    	cv::imshow("第二张图片进行直方图反投影",result);
    
    	//利用位运算消除低饱和度像素
    	cv::bitwise_and(result,v[1],result);
    	cv::namedWindow("第二张图片利用位运算进一步消除低饱和度像素点");
    	cv::imshow("第二张图片利用位运算进一步消除低饱和度像素点",result);
    
    	// 得到反投影直方图概率图像
    	finder.setThreshold(-1.0f);
    	result= finder.find(hsv,0.0f,180.0f,ch,1);
    	cv::bitwise_and(result,v[1],result);
    	cv::namedWindow("第二张图片处理后的二值图像");
    	cv::imshow("第二张图片处理后的二值图像",result);
    
    	cv::Rect rect(85,200,64,64);
    	cv::rectangle(image, rect, cv::Scalar(0,0,255));
    
    	cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
    	cout << "均值漂移迭代次数 = " << cv::meanShift(result,rect,criteria) << endl;
    
    	cv::rectangle(image, rect, cv::Scalar(0,255,0));
    
    	//展示结果图
    	cv::namedWindow("查找结果,红框为第一幅图中篮球位置,绿框为现位置");
    	cv::imshow("查找结果,红框为第一幅图中篮球位置,绿框为现位置",image);
    
    	cv::waitKey();
    	return 0;
    }

    输出结果
















                                      -END-







  • 相关阅读:
    Android 3.0 r1 API中文文档(108) —— ExpandableListAdapter
    Android 3.0 r1 API中文文档(113) ——SlidingDrawer
    Android 3.0 r1 API中文文档(105) —— ViewParent
    Android 中文 API (102)—— CursorAdapter
    Android开发者指南(4) —— Application Fundamentals
    Android开发者指南(1) —— Android Debug Bridge(adb)
    Android中文API(115)——AudioFormat
    Android中文API(116)——TableLayout
    Android开发者指南(3) —— Other Tools
    Android中文API (110) —— CursorTreeAdapter
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3799164.html
Copyright © 2011-2022 走看看