一、简介

图像直方图的反向投影是一个概率分布图,表示一个指定图像片段出现在特定位置的概率。当我们已知图像中某个物体的大体位置时,可以通过概率分布图找到物体在另一张图像中的准确位置。我们可以设定一个初始位置,在其周围反复移动来提高局部匹配概率,从而找到物体的准确位置,这个实现过程叫做均值平移算法。

二、实现过程

因为人物的面部特征相对于其他位置更明显,本次实验主要应用于人物的面部识别。

1、设定感兴趣的区域

感兴趣区域的设定有两种方式,一种是已知图片人物脸部位置的像素坐标,通过设定矩形框来定位到人物脸部位置,另一种是使用opencv自带的selectROI函数,手动框选自己感兴趣的位置。

2、获取脸部直方图并做归一化

设置一个ColorHistogram类增加一个获取色调直方图的函数getHueHistogram。此函数包含将图像转换成HSV色彩空间,屏蔽低饱和度的像素(可能用到,也可能用不到),计算图像直方图。

cv::Mat getHueHistogram(const cv::Mat &image2, int minSaturation = 0){cv::Mat hist;//转换成HSV色彩空间cv::Mat hsv;cv::cvtColor(image2, hsv, CV_BGR2HSV);//cv::imshow("hsv", hsv);//掩码(可能用的到也可能用不到)cv::Mat mask;if (minSaturation > 0) {std::vector<cv::Mat>v;cv::split(hsv, v);  //将3个通道分割进3幅图像cv::threshold(v[1], mask, minSaturation, 255, cv::THRESH_BINARY);//屏蔽低饱和度的像素}//准备一维色调直方图的参数hranges[0] = 0.0;hranges[1] = 180.0;  //范围是0~180channels[0] = 0;   //色调通道//计算直方图cv::calcHist(&hsv, 1,   //仅为一幅图像的直方图channels,             //使用的通道mask,                 //二值掩码hist,                 //作为结果的直方图1,                    //这是一维的直方图histSize,             //箱子数量ranges);              //像素值的范围return hist;}

然后,对获取的直方图做归一化。

void setHistogram(const cv::Mat& h) {histogram = h;cv::normalize(histogram, histogram, 1.0);}

3、反向投影,用meanshift查找目标

打开第二张图像,并将其转换成HSV色彩空间(代码中对输入的图像做了resize,避免有些图像尺寸过大,显示不全),然后对第一幅图像的直方图做反向投影。下面result是反向投影的结果,目前是框选了路飞的脸部作为感兴趣区域,如果框选路飞的帽子,反向投影会有不一样的效果,大家可以自己尝试。

//打开第二幅图像,并转换成HSV,对第一幅图像的直方图做反向投影image = cv::imread("lufei2.JPG");resize(image, image3, cv::Size(500, 700));cv::cvtColor(image3, hsv, CV_BGR2HSV); //转换成HSV色彩空间int ch[1] = { 0 };cv::Mat result = finder.find(hsv, 0.0f, 180.0f, ch);

使用openCV的meanshift算法可以将初始矩形区域修改成图像人物脸部的新位置。

cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,10, // 最多迭代10 次1); // 或者重心移动距离小于1 个像素cv::meanShift(result, rect, criteria);

至此,就找到了另一张图像中人物的脸部。

三、其他实验结果

除了进行从单人图像找另一个单人图像的实验,还做了从单人图像找多人合影的图像,下面是对NBA球星做的一个实验。

四、部分原理补充

本实验为了突出感兴趣目标特征,使用了HSV色彩空间的色调分量,使用CV_BGR2HSV标志转换图像后,得到的第一个通道就是色调分量。这是一个8位分量,值范围为0~180(如果使用cv::cvtColor,转换后的图像与原始图像的类型就会是相同的)。为了提取色调图像,cv::split 函数把三通道的 HSV 图像分割成三个单通道图像。这三幅图像存放在一个 std::vector 实例中,并且色调图像是向量的第一个入口(即索引为 0)。

在使用颜色的色调分量时,要把它的饱和度考虑在内(饱和度是向量的第二个入口),当颜色的饱和度很低时,它的色调信息就会变得不稳定且不可靠。这是因为低饱和度颜色的 B、G 和 R 分量几乎是相等的,这导致很难确定它所表示的准确颜色。因此,在 getHueHistogram 方法中使用 minSat 参数屏蔽掉饱和度低于此阈值的像素,不把它们统计进直方图中。

均值偏移算法是一个迭代过程,用于定位概率函数的局部最大值,方法是寻找预定义窗口内部数据点的重心或加权平均值。然后,把窗口移动到重心的位置,并重复该过程,直到窗口中心收敛到一个稳定的点。OpenCV 实现该算法时定义了两个停止条件:迭代次数达到最大值 (MAX_ITER);窗口中心的偏移值小于某个限值(EPS),可认为该位置收敛到一个稳定点。这两个条件存储在一个 cv::TermCriteria 实例中。

五、完整代码

#include <iostream>
#include<Windows.h>
#include<opencv2/core.hpp>    //图像数据结构的核心
#include<opencv2/highgui.hpp> //所有图形接口函数
#include<opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;//获得色调直方图
class ColorHistogram
{
private:int histSize[3]; // 每个维度的大小float hranges[2]; // 值的范围(三个维度用同一个值)const float* ranges[3]; // 每个维度的范围int channels[3]; // 需要处理的通道public:ColorHistogram() {// 准备用于彩色图像的默认参数// 每个维度的大小和范围是相等的histSize[0] = histSize[1] = histSize[2] = 256;hranges[0] = 0.0; // BGR 范围为0~256hranges[1] = 256.0;ranges[0] = hranges; // 这个类中ranges[1] = hranges; // 所有通道的范围都相等ranges[2] = hranges;channels[0] = 0; // 三个通道:Bchannels[1] = 1; // Gchannels[2] = 2; // R}//计算一维直方图,BGR的原图转换成HSV,忽略低饱和度的像素cv::Mat getHueHistogram(const cv::Mat &image2, int minSaturation = 0){cv::Mat hist;//转换成HSV色彩空间cv::Mat hsv;cv::cvtColor(image2, hsv, CV_BGR2HSV);//cv::imshow("hsv", hsv);//掩码(可能用的到也可能用不到)cv::Mat mask;if (minSaturation > 0) {std::vector<cv::Mat>v;cv::split(hsv, v);  //将3个通道分割进3幅图像cv::threshold(v[1], mask, minSaturation, 255, cv::THRESH_BINARY);//屏蔽低饱和度的像素}//准备一维色调直方图的参数hranges[0] = 0.0;hranges[1] = 180.0;  //范围是0~180channels[0] = 0;   //色调通道//计算直方图cv::calcHist(&hsv, 1,   //仅为一幅图像的直方图channels,             //使用的通道mask,                 //二值掩码hist,                 //作为结果的直方图1,                    //这是一维的直方图histSize,             //箱子数量ranges);              //像素值的范围return hist;}};class ContentFinder {
private:// 直方图参数float hranges[2];const float* ranges[3];int channels[3];float threshold; // 判断阈值cv::Mat histogram; // 输入直方图
public:ContentFinder() : threshold(0.1f) {// 本类中所有通道的范围相同ranges[0] = hranges;ranges[1] = hranges;ranges[2] = hranges;}// 对直方图做归一化void setHistogram(const cv::Mat& h) {histogram = h;cv::normalize(histogram, histogram, 1.0);}// 查找属于直方图的像素cv::Mat find(const cv::Mat& image, float minValue, float maxValue,int *channels) {cv::Mat result;hranges[0] = minValue;hranges[1] = maxValue;// 直方图的维度数与通道列表一致for (int i = 0; i < histogram.dims; i++)this->channels[i] = channels[i];cv::calcBackProject(&image, 1, // 只使用一幅图像channels, // 通道histogram, // 直方图result, // 反向投影的图像ranges, // 每个维度的值范围255.0 // 选用的换算系数// 把概率值从1 映射到255);cv::imshow("result", result);return result;}
};int main()
{/************均值检测meanshift***********/cv::Mat image = cv::imread("ZMS1.jpg");cv::Mat image2;cv::Mat image3;cv::Mat hsv;resize(image, image2, cv::Size(500, 700));cv::Rect rect;rect = cv::selectROI("image", image2, false, false);cv::Mat imageROI = image2(rect).clone();//手动框选/*cv::Rect rect(227, 108, 108, 104);cv::Mat imageROI = image2(rect);*///手动设置矩形框选范围cv::rectangle(image2, rect, cv::Scalar(255, 0, 0), 1, cv::LINE_8, 0);cv::imshow("image2", image2);//得到人脸直方图int minsat = 65;  //最小饱和度ColorHistogram hc;cv::Mat colorhist = hc.getHueHistogram(imageROI, minsat);//把直方图传给ContentFinder类ContentFinder finder;finder.setHistogram(colorhist);//对直方图做归一化//打开第二幅图像,并转换成HSV,对第一幅图像的直方图做反向投影image = cv::imread("ZMS2.JPG");resize(image, image3, cv::Size(500, 700));cv::cvtColor(image3, hsv, CV_BGR2HSV); //转换成HSV色彩空间int ch[1] = { 0 };cv::Mat result = finder.find(hsv, 0.0f, 180.0f, ch);cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,10, // 最多迭代10 次1); // 或者重心移动距离小于1 个像素cv::meanShift(result, rect, criteria);cv::rectangle(image3, rect, cv::Scalar(0, 255, 0), 1, cv::LINE_8, 0);cv::imshow("image3", image3);waitKey(0);
}

本篇文章是我学习opencv做的笔记,可能存在许多不足,欢迎大家批评指正!有问题可以随时和我交流。

openCV中meanshift算法查找目标相关推荐

  1. OpenCV中MeanShift算法视频移动对象分析

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 MeanShift算法 Mean Shift是一种聚类算法,在数据 ...

  2. 目标跟踪学习笔记_1(opencv中meanshift和camshift例子的应用)

    在这一节中,主要讲目标跟踪的一个重要的算法Camshift,因为它是连续自使用的meanShift,所以这2个函数opencv中都有,且都很重要.为了让大家先达到一个感性认识.这节主要是看懂和运行op ...

  3. opencv中meanshift和camshift函数的使用

    原文地址:http://www.360doc.com/content/13/1106/16/10724725_327176222.shtml 在这一节中,主要讲目标跟踪的一个重要的算法Camshift ...

  4. 目标跟踪之camshift---opencv中meanshift和camshift例子的应用

    在这一节中,主要讲目标跟踪的一个重要的算法Camshift,因为它是连续自使用的meanShift,所以这2个函数opencv中都有,且都很重要.为了让大家先达到一个感性认识.这节主要是看懂和运行op ...

  5. python opencv入门 Meanshift 和 Camshift 算法(40)

    内容来自OpenCV-Python Tutorials 自己翻译整理 目标: 在本章,学习Meanshift算法和Camshift算法来寻找和追踪视频中的目标物体. Meanshift算法: mean ...

  6. matlab中partdata,[转载]meanshift算法

    Mean Shift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束. 1. Meanshift推导 给定d维空间R ...

  7. 干货 | OpenCV中KLT光流跟踪原理详解与代码演示

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 稀疏光流跟踪(KLT)详解 在视频移动 ...

  8. opencv入门跟踪算法(3)之camshift

    二.算法原理 1.camshift利用目标的颜色直方图模型将图像转换为颜色概率分布图,初始化一个搜索窗的大小和位置,并根据上一帧得到的结果自适应调整搜索窗口的位置和大小,从而定位出当前图像中目标的中心 ...

  9. 二值图像分析:OpenCV中的二值化阈值操作

    二值图像分析:OpenCV中的二值化阈值操作 1.二值图像的定义 2.OpenCV中的基本阈值操作 3.OTSU二值寻找算法 3.1 OTSU二值寻找算法介绍 3.2 OTSU二值寻找算法分析 3.2 ...

最新文章

  1. jsp常见获取地址函数之间的不同
  2. M1事后分析报告--We have power to change the origin state
  3. 在django中使用django_debug_toolbar
  4. 一打开就致命错误_CAD|致命错误|解决方法
  5. 温州大学《机器学习》课程代码(二)(回归)
  6. Gitlab添加SSH密钥的解决办法
  7. 使用IntelliJ IDEA和Maven管理搭建+Web+Tomcat开发环境
  8. 使用 nw-builder 构建跨平台桌面应用程序
  9. java锁的概念,Java ReentrantLock锁机制概念篇
  10. C++设置不定参数方法 简单示例
  11. mysql使用substring_index达到splite功能
  12. 64位操作系统 mysql_MySQL学习第三天 Windows 64位操作系统下验证MySQL
  13. 深入理解jvm 读后感
  14. VM VirtualBox Centos6.5安装Oracle 11g r2 RAC
  15. 人世之厄人性之恶——陈应松《母亲》读后
  16. NXP TJA1043 datasheet 知识点记录
  17. 张家界3天旅游攻略(带你的想象给我游玩一遍)
  18. 《前端开发者的进阶之路》
  19. 编程中无穷大的设定 很多人可能设为0x7fffffff,这个数的确是32-bit int的最大值,符号位为0,其他的都是1 但在很多情况下,0x7fffffff会出现错误,比如溢出,这样两个无穷大数相
  20. 2011年7月编程语言排行榜,Objective-C将成为年度语言

热门文章

  1. 开源网站:代码搜索网站
  2. 文案策划没思路?来看老前辈经验分享
  3. 公有云和私有云的区别 如何搭建云存储
  4. 互联网早报:微信红包封面升级:支持个人定制...
  5. R和RStudio的安装
  6. 基于深度模型Out of Distribution(OOD)基础技术路线研究
  7. Discuss on closure
  8. C语言的system()函数详解
  9. 读书笔记-第一本Docker书:Docker简介
  10. nowcoder 左神算法1