反向投影直方图功能
- 根据特定感兴趣区域(ImageROI)的直方图特征,计算原图中属于各直方图箱子的概率,推断原图属于感兴趣区域的部分。
反向投影直方图原理
- 划定感兴趣区域(ImageROI)并计算直方图,可以设定箱子数量(如8)。
- 对直方图进行归一化处理
cv::normalize
,得到属于各箱子的概率。 - 对于原图的每个像素,都在对应直方图的箱子中找到概率,并*255赋值给对应像素,并生成图像。
- 可以设定阈值概率来生成二值图。
封装的ContentFinder类
//------------------【程序说明】----------------------
//本头文件为反向映射直方图等功能封装ContentFinder类
//创建时间:2020/12/21 作者:Eric 南京航空航天大学
//----------------------------------------------------
//-------------【修改和读取参数接口】-----------------
//1.设定阈值
//2.读取阈值
//3.设置参考直方图
//4.设置参考直方图(稀疏矩阵)
//----------------------------------------------------
//-----------------【具体功能】-----------------------
//1.反向投影直方图简易版本
//2.反向投影直方图复杂版本
//----------------------------------------------------
#pragma once
#include<opencv2/opencv.hpp>
class ContentFinder
{
private:
//直方图参数
float hranges[2]; //值范围(三个维度用一个值)
const float* ranges[3]; //值范围的指针,用于指向值范围
int channels[3]; //要计算的通道
float threshold; //判断阈值
cv::Mat histogram; //输入直方图
cv::SparseMat shistogram; //输入稀疏矩阵类直方图
bool isSparse; //判定是否为稀疏矩阵
public:
//默认构造
ContentFinder()
{
threshold = 0.1f;
isSparse = false;
hranges[0] = 0.0; //默认范围从0(含)
hranges[1] = 256.0; //到256(不含)
ranges[0] = hranges; //值范围指针指向值范围
ranges[1] = hranges; //三个通道范围都相等
ranges[2] = hranges;
channels[0] = 0; //通道B
channels[1] = 1; //通道G
channels[2] = 2; //通道R
}
//设定阈值
void setThreshold(float t)
{
threshold = t;
}
//读取阈值
float getThreshold()
{
return threshold;
}
//设置参考直方图
void setHistogram(const cv::Mat& h)
{
isSparse = false;
cv::normalize(h, histogram, 1.0);
}
//设置参考直方图(稀疏矩阵)
void setHistogram(const cv::SparseMat& h)
{
isSparse = true;
cv::normalize(h, shistogram, 1.0, cv::NORM_L2);
}
//反向投影直方图简易版本
//使用全部通道,范围为[0,256)
cv::Mat find(const cv::Mat& image)
{
cv::Mat result;
hranges[0] = 0.0; //默认范围从0(含)
hranges[1] = 256.0; //到256(不含)
//调用反向投影直方图复杂版本
return find(image, hranges[0], hranges[1]);
}
//反向投影直方图复杂版本
//使用全部通道,可设定范围
cv::Mat find(const cv::Mat& image, float minValue, float maxValue)
{
cv::Mat result;
hranges[0] = minValue;
hranges[1] = maxValue;
//如果不是稀疏矩阵
if (!isSparse)
{
//调用反向投影直方图
cv::calcBackProject
( &image, //源图像地址
1, //一幅图像
channels, //通道(地址)
histogram, //使用的直方图
result, //反向投影的结果矩阵
ranges, //像素范围(双地址)
255.0 //缩放因子的选择使得直方图值1映射到255
);
}
else
{
//调用稀疏矩阵反向投影直方图
cv::calcBackProject
( &image, //源图像地址
1, //一幅图像
channels, //通道(地址)
shistogram, //使用的直方图
result, //反向投影的结果矩阵
ranges, //像素范围(双地址)
255.0 //缩放因子的选择使得直方图值1映射到255
);
}
//阈值反投影得到二值图像
if (threshold > 0.0)
cv::threshold(result, result, 255.0 * threshold, 255.0, cv::THRESH_BINARY);
return result;
}
};
补充:cv::calcBackProject
函数的使用
函数签名
CV_EXPORTS void calcBackProject( const Mat* images, int nimages,
const int* channels, InputArray hist,
OutputArray backProject, const float** ranges,
double scale = 1, bool uniform = true );
参数分别是:源图像地址,一幅图像,通道地址,输入直方图,输出图像,范围双指针,换算系数(这里由于归一化了要设为255),每个箱子均匀(1)。
实际演示(需要4.2的ColorHistogram
类)
void reverseSkyProjection()
{
cv::Mat prairie = cv::imread("prairie.jpg");
ColorHistogram hc;
//提取天空区域
cv::Mat ImageROI = prairie(cv::Rect(0, 0, 500, 200));
cv::imshow("sky", ImageROI);
hc.setSize(8);
//得到天空区域直方图
cv::Mat shist = hc.getHistogram(ImageROI);
//创建反向映射直方图类
ContentFinder finder;
finder.setHistogram(shist);
//阈值概率设为0.05
finder.setThreshold(0.05);
cv::Mat result = finder.find(prairie);
cv::imshow("prairie", prairie);
cv::imshow("projected sky", result);
}
void reverseCloudProjection()
{
cv::Mat prairie = cv::imread("prairie.jpg");
ColorHistogram hc;
//提取云朵区域
cv::Mat ImageROI = prairie(cv::Rect(50, 50, 100, 100));
cv::imshow("cloud", ImageROI);
hc.setSize(8);
//得到云朵区域直方图
cv::Mat shist = hc.getHistogram(ImageROI);
//创建反向映射直方图类
ContentFinder finder;
finder.setHistogram(shist);
//阈值概率设为0.05
finder.setThreshold(0.05);
cv::Mat result = finder.find(prairie);
cv::imshow("prairie", prairie);
cv::imshow("projected cloud", result);
}
效果
提取天空
提取云朵