为了方便调用,我将opencv2许多常用的函数以及功能都封装在一个类里面,所以这次的均值漂移算法也将从封装类中截取出来,供大家学习
类的代码:
class Package
{
private:
public:
Rect MeanShitfMath(const Mat &OrgInImage, const Mat &PreInImage, Rect &ROIrect);
};
Rect Package::MeanShitfMath(const Mat &OrgInImage, const Mat &PreInImage, Rect &ROIrect)
{
Mat orgimg = OrgInImage;
Mat preimg = PreInImage;
/*先对输入的原始图像进行感兴趣区域的采集*/
//先获取感兴趣区域的图像
Mat bgrROI = orgimg(ROIrect);
//将感兴趣区域的BGR空间转换为HSV空间
Mat hsvROI;
cvtColor(bgrROI, hsvROI, CV_BGR2HSV);
//获取感兴趣区域的HSV空间的S空间
vector<Mat>hsvROIvector;
split(hsvROI, hsvROIvector);
//将S通道的阀值化
threshold(hsvROIvector[1], hsvROIvector[1], 65, 255.0, THRESH_BINARY);
//计算S通道的直方图
float hranges[2];
const float* ranges[1];
int channels[1];
MatND hsvROIhist;
int histSize[1];
hranges[0] = 0.0;
hranges[1] = 180.0;
ranges[0] = hranges;
channels[0] = 0;
histSize[0] = 256;
calcHist(&hsvROIvector[1], 1, channels, Mat(), hsvROIhist, 1, histSize, ranges);
//归一化直方图
normalize(hsvROIhist, hsvROIhist, 1.0);
/*在输入的第二幅图像中进行均值漂移算法*/
Mat prehsv;
cvtColor(preimg, prehsv, CV_BGR2HSV);
vector<Mat>prehsvvector;
split(prehsv, prehsvvector);
/*threshold(prehsvvector[1], prehsvvector[1], 65, 255.0, THRESH_BINARY);*/
//在第二幅图上获取感兴趣区域的直方图的反投影
Mat result;
calcBackProject(&(prehsvvector[1]), 1, channels, hsvROIhist, result, ranges, 255.0);
threshold(result, result, 255 * (-1.0f), 255.0, THRESH_BINARY);
bitwise_and(result, prehsvvector[1], result);
/*rectangle(preimg, ROIrect, Scalar(0, 0, 255));*/
//meanshift算法
TermCriteria criteria(TermCriteria::MAX_ITER, 10, 0.01);
meanShift(result, ROIrect, criteria);
/*rectangle(preimg, ROIrect, Scalar(0, 255, 0));*/
return ROIrect;
}
基本思路:
1、先在输入的原始图像中找到感兴趣的区域,并将这个感兴趣区域的直方图计算出来(不过这次计算的直方图不是BGR空间下的,而是HSV空间下的,所以需要
先转换颜色空间),也不再是得到改感兴趣区域某一个通道下的直方图信息,而是得到HSV空间的S通道的改感兴趣区域的直方图(需分解)
2、然后就是在第二幅图像中将上一部得到的感兴趣区域的S通道的直方图进行反投影,反投影到第二幅图像中的S通道上
3、反投影完成后就开始进行meanshift算法
返回的是一个Rect类型的矩形区域,这个矩形是通过均值漂移算法在另一张图中找到的相似的区域,在主函数中可以用rectangle函数降其显示出来
测试代码:
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<iostream>
#include<vector>
#include<opencv2/nonfree/features2d.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/video/tracking.hpp>
using namespace cv;
using namespace std;
class Package
{
private:
public:
Rect MeanShitfMath(const Mat &OrgInImage, const Mat &PreInImage, Rect &ROIrect);
};
Rect Package::MeanShitfMath(const Mat &OrgInImage, const Mat &PreInImage, Rect &ROIrect)
{
Mat orgimg = OrgInImage;
Mat preimg = PreInImage;
/*先对输入的原始图像进行感兴趣区域的采集*/
//先获取感兴趣区域的图像
Mat bgrROI = orgimg(ROIrect);
//将感兴趣区域的BGR空间转换为HSV空间
Mat hsvROI;
cvtColor(bgrROI, hsvROI, CV_BGR2HSV);
//获取感兴趣区域的HSV空间的S空间
vector<Mat>hsvROIvector;
split(hsvROI, hsvROIvector);
//将S通道的阀值化
threshold(hsvROIvector[1], hsvROIvector[1], 65, 255.0, THRESH_BINARY);
//计算S通道的直方图
float hranges[2];
const float* ranges[1];
int channels[1];
MatND hsvROIhist;
int histSize[1];
hranges[0] = 0.0;
hranges[1] = 180.0;
ranges[0] = hranges;
channels[0] = 0;
histSize[0] = 256;
calcHist(&hsvROIvector[1], 1, channels, Mat(), hsvROIhist, 1, histSize, ranges);
//归一化直方图
normalize(hsvROIhist, hsvROIhist, 1.0);
/*在输入的第二幅图像中进行均值漂移算法*/
Mat prehsv;
cvtColor(preimg, prehsv, CV_BGR2HSV);
vector<Mat>prehsvvector;
split(prehsv, prehsvvector);
/*threshold(prehsvvector[1], prehsvvector[1], 65, 255.0, THRESH_BINARY);*/
//在第二幅图上获取感兴趣区域的直方图的反投影
Mat result;
calcBackProject(&(prehsvvector[1]), 1, channels, hsvROIhist, result, ranges, 255.0);
threshold(result, result, 255 * (-1.0f), 255.0, THRESH_BINARY);
bitwise_and(result, prehsvvector[1], result);
/*rectangle(preimg, ROIrect, Scalar(0, 0, 255));*/
//meanshift算法
TermCriteria criteria(TermCriteria::MAX_ITER, 10, 0.01);
meanShift(result, ROIrect, criteria);
/*rectangle(preimg, ROIrect, Scalar(0, 255, 0));*/
return ROIrect;
}
Package P;
int main()
{
Mat img1 = imread("F:\\baboon1.jpg");
Mat img2 = imread("F:\\baboon3.jpg");
rectangle(img1, Rect(110, 260, 35, 40), Scalar(0, 255, 255));
namedWindow("img1");
imshow("img1", img1);
Rect rect = P.MeanShitfMath(img1, img2, Rect(110, 260, 35, 40));
rectangle(img2, rect, Scalar(255, 0, 0));
namedWindow("result");
imshow("result", img2);
waitKey(0);
return 0;
}
各位博友,如果要转载的话,请注明出处!!!
谢谢各位了