【OpenCv】三天学会C++/OPENCV2基本操作之直方图应用(均值飘逸(Mean Shift)查找物体)

 

ColorHistogram.cpp获取直方图后,可以对直方图均衡化,通过查找表修改图像外观,在此不再详述,有兴趣可以自己尝试,直方图是图像内容的重要特性,如果某个区域中显示独特的纹理或者独特的物体,那么这个区域的直方图可以看做一个概率函数,它给出的是某个像素属于该纹理或者物体的概率。反投影直方图的结果是一个概率映射,体现了已知的图像内容出现在图像中特定位置的概率。假设我们已经知道物体的近似位置,概率映射可用于找到对象的确切位置。最有可能的位置是在已知窗口区域中得到最大概率的位置。通过从初始位置开始迭代移动,便可以找到物体的位置。这就是均值漂移算法。

假设我们想要找的位置是双目视觉中右图的花朵,我们要用HSV颜色空间的色调(HUE)来描述它。

主函数:

#include "stdafx.h"
#include "ColorHistogram.h"
#include "ObjectFinder.h"
#include <opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\video\video.hpp>

int main(void)
{
	GetHistogram gh;
	ObjectFinder of;
	cv::Mat img1, img2;
	cv::Mat imgROI;
	cv::Mat histogram;
	cv::Mat backProject;

	img1 = cv::imread("imR.png");
	if(!img1.data)
		return 0;

	imgROI = img1(cv::Rect(70,0,20,20));
	cv::rectangle(img1,cv::Rect(70,0,20,20),cv::Scalar(0,0,255));
	cv::namedWindow("img1");
	cv::imshow("img1", img1);
	//获得imgROI的直方图
	histogram = gh.getHueHistogram(imgROI, 65);
	cv::normalize(histogram,histogram,1.0);
	of.setHistogram(histogram);
	//获取并处理第二幅图像
	cv::Mat hsv; 
	std::vector<cv::Mat> hue;
	img2 = cv::imread("imL.png");
	cv::cvtColor(img2, hsv, CV_BGR2HSV);
	cv::split(hsv, hue);
	cv::threshold(hue[1], hue[1], 10, 255, cv::THRESH_BINARY);//这个是为了将低饱和度的图像从反向投影结果中剔除
	//对于第二幅图进行反向投影,使用第一幅图ROI的直方图
	backProject = of.finder(img2);
	cv::bitwise_and(backProject, hue[1], backProject);
	cv::namedWindow("backProject");
	cv::imshow("backProject",backProject);
	//均值漂移
	cv::Rect rect(70,0,20,20);
	cv::rectangle(img2, rect, cv::Scalar(0,0,255));
	cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,100,0.01);//最大迭代次数是10,移动距离阈值是0.01
	cv::meanShift(backProject,rect,criteria);
	cv::rectangle(img2, rect, cv::Scalar(0,255,0));
	cv::namedWindow("img2");
	cv::imshow("img2",img2);

	cv::waitKey(0);
	return 0;
}

ColorHistogram.cpp 

#include "stdafx.h"
#include"ColorHistogram.h"

//获得色相的直方图
cv::MatND GetHistogram::getHueHistogram(const cv::Mat &image, int minSaturation)
{
	cv::MatND hist;
	cv::Mat hsv;
	cv::cvtColor(image, hsv, CV_BGR2HSV);
	std::vector<cv::Mat> hue;
	cv::split(image, hue);
	cv::Mat mask; 
	//将低饱和度的像素从掩码中去掉
	if (minSaturation > 0)
		cv::threshold(hue[1], mask, minSaturation, 255, cv::THRESH_BINARY);
	cv::calcHist(&hue[0],
		1,
		HueChannels,
		mask,
		hist,
		1,
		HueHistSize,
		HueBinRanges
		);
	return hist;
}

ObjectFinder.cpp

#include "stdafx.h"
#include"ObjectFinder.h"

cv::Mat ObjectFinder::finder(const cv::Mat &image)
{
	cv::Mat backProject;
	cv::Mat hsv;
	std::vector<cv::Mat> hue;
	cv::cvtColor(image, hsv, CV_BGR2HSV);
	cv::split(hsv, hue);
	cv::calcBackProject(&hue[1],
		1,
		HueChannels,
		histogram,
		backProject,
		HueBinRanges,
		255.0
		);
	return backProject;
}

ColorHistogram.h

#if !defined GETHISTOGRAM_H
#define GETHISTOGRAM_H

#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>

class GetHistogram
{
private:
	//calchist中的参数
	int HueChannels[1];

	int HueHistSize[1] ;

	float HueValueRanges[2];

	const float *HueBinRanges[1] ;

public:
	GetHistogram()
	{
		HueChannels[0] = 0;

		HueHistSize[0] = 180;

		HueValueRanges[0] = 0.0;
		HueValueRanges[1] = 180.0;

		HueBinRanges[0] = HueValueRanges;
	}
	//获得色相的直方图
	cv::MatND getHueHistogram(const cv::Mat &image, int minSaturation);
};

#endif

ObjectFinder.h

#if !defined OBJECTFINDER_H
#define OBJECTFINDER_H

#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>

class ObjectFinder
{
private:
	//calcBackProject的参数
	int HueChannels[1];
	cv::MatND histogram;
	float HueValueRanges[2];
	const float *HueBinRanges[1];


public:
	ObjectFinder()
	{
		HueChannels[0] = 0;
		HueValueRanges[0] = 0.0;
		HueValueRanges[1] = 180.0;
		HueBinRanges[0] = HueValueRanges;
	}
	//得到calcHist的直方图
	void setHistogram(cv::MatND hist)
	{
		histogram = hist;
	}
	//利用直方图对图像反向投影
	cv::Mat finder(const cv::Mat &image);
};

#endif

我写的过程中虽然参考了书籍和教程,但是错误很多,后悔的是花掉了一个多小时的时间,而这个跟我研究的课题没有什么太大的关系,索性的是这是一个锻炼的过程,同时也了解了一些关于目标跟踪的原理。

效果也一般,如下:

红色为原来位置,绿色为跟踪后的位置,算法属于暴力迭代搜索,阈值还需要自己不断调整,我分析效果不好的原因是因为花朵的图案本身重复的问题,这类目标跟踪算法可能适合的是比较独特或色彩区分度高的图像,有兴趣的朋友可以了解一下均值漂移,在这里就不深入探讨了,仅仅是了解直方图的应用和编程技巧。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值