赞
踩
直方图广泛运用于很多计算机视觉运用当中,通过标记帧与帧之间显著的边缘和颜色的统计变化,来检测视频中场景中场景的变化。在每个兴趣点设置一个有相近特征的直方图所构成"标签",用以确定图像中的兴趣点。边缘、色彩、角度等方图构成了可以被传递给目标识别分类器的一个通用特征类型。色彩和边缘的直方图序列还可以用来识别网络视频是否被复制。
其实,简单点说,直方图就是对数据进行统计的一种方法,并且将统计值组织到一系列事先定义好的bin当中。其中,bin为直方图中经常用到的一个概念,可翻译为“直条”或“组距”,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。且无论如何,直方图获得的是数据分布的统计图。通常直方图的维数要低于原始数据。总而言之,直方图是计算机视觉中最经典的工具之一。
其实,简单点说,直方图就是对数据进行统计的一种方法,并且将统计值组织到一系列事先定义好的bin当中。其中,bin为直方图中经常用到的一个概念,可翻译为“直条”或“组距”,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。且无论如何,直方图获得的是数据分布的统计图。通常直方图的维数要低于原始数据。总而言之,直方图是计算机视觉中最经典的工具之一。
在统计学中,直方图(Histogram)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本和该样本对应的某个属性的度量。
我们在图像变换的那一章中讲过直方图的均衡化,它是通过拉伸像素强度分布范围来增强图像对比度的一种方法。大家在自己的心目中应该已经对直方图有一定的理解和认知。下面就来看一看对图像直方图比较书面化的解释。
图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数。可以借助观察该直方图了解需要如何调整亮度分布。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。计算机视觉领域常借助图像直方图来实现图像的二值化。
直方图的意义如下。
描述图像的特征。下面看一个例子,假设有一个矩阵包含一张图像的信息(灰度值0-255),让我们按照某种方式来统计这些数字。既然已知数字的范围包含256个值,于是可以将这个范围分割成子区域(也就是上面讲到bins),如:
![[0,255]=[0,15]U[16,31]U…U[240,255]
range = bin1U bin2U…Ubinn=15](https://img-blog.csdnimg.cn/5f55e816dab643ee94d59e332517a408.png)
然后再统计每一个bini的像素数目。采用这一方法来统计上面的数字矩阵。

以上就是一个说明直方图的用途的简单示例。其实,直方图并不局限于统计颜色灰度,而是可以统计任何图像特征,如梯度、方向等。
让我们具体讲讲直方图的一些术语和细节。
void calcHish(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float ** ranges,bool uniform=true, bool accumulate=false)
void minMaxLoc(InputArray src, double* minVal, double* maxVal=0,Point* minLoc=0,Point* maxLoc=0,InputArray mask=noArray())
注意:色调(Hue)、饱和度(Saturation)。所以H-S直方图就是色调——饱和度直方图。
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat srcImage, hsvImage;
srcImage = imread("../../image/1.tif");
cvtColor(srcImage, hsvImage, COLOR_BGR2HSV);
//参数准备
//将色调量化为30个等级,将饱和度量化为32个等级
int hueBinNum = 30; //色调的直方图直条数量
int saturationBinNum = 32; //饱和度的直方图直条数量
int histSize[] = { hueBinNum, saturationBinNum };
//定义色调的范围为0-179
float hueRnages[] = { 0,180 };
//定义饱和度的变化范围为0-255
float saturationRanges[] = { 0,256 };
const float* ranges[] = { hueRnages,saturationRanges };
MatND dstHist;
//参数准备,calHist函数中将计算第0通道和第1通道的直方图
int channels[] = { 0,1 };
calcHist(&hsvImage,//输入的数组
1,//数组个数为1
channels,
Mat(),//不适掩膜
dstHist,
2,//需要计算的直方图的维度为2
histSize,//存放每个维度的直方图尺寸的数组
ranges,//每一维数值的取值范围数组
true,//指示直方图是否均匀的标识符
false//累计标识符
);
double maxValue = 0;
minMaxLoc(dstHist, 0, &maxValue, 0, 0);
int scale = 10;
Mat histImage = Mat::zeros(saturationBinNum * scale, hueBinNum * scale, CV_8UC3);
//进行直方图绘制
for (int hue = 0; hue < hueBinNum; hue++) {
for (int saturation = 0; saturation < saturationBinNum; saturation++) {
float binValue = dstHist.at<float>(hue, saturation);//直方图的值
int intensity = cvRound(binValue * 255 / maxValue); //轻度
//正式绘制
rectangle(histImage, Point(hue * scale, saturation * scale),
Point((hue+1)*scale-1,(saturation+1)*scale-1),Scalar::all(intensity),FILLED);
}
}
imshow("素材图", srcImage);
imshow("H-s直方图", histImage);
waitKey();
}

compareHist()函数用于对两幅直方图进行比较。与两个版本的C++原型。
double compareHist(InputArray H1, InputArray H2, int method)
double compareHist(const SparseMat &H1, const SparseMat &H2)

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat srcImage_base, hsvImage_base;
Mat srcImage_test1, hsvImage_test1;
Mat srcImage_test2, hsvImage_test2;
Mat hsvImage_halfDown;
//载入基准图像和两张测试图像
srcImage_base = imread("1.jpg", 1);
srcImage_test1 = imread("2.jpg", 1);
srcImage_test2 = imread("3.jpg", 1);
//显示载入的3张图像
imshow("基准 图像", srcImage_base);
imshow("测试图像1", srcImage_test1);
imshow("测试图像2", srcImage_test2);
//将图像有BGR色彩空间转换到HSV色彩空间
cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
cvtColor(srcImage_test2, hsvImage_test2, COLOR_BGR2HSV);
//创建包含基准图像下半部的半身图像
hsvImage_halfDown = hsvImage_base(Range(hsvImage_base.rows / 2,
hsvImage_base.rows - 1), Range(0, hsvImage_base.cols - 1));
//初始化计算直方图需要的实参
int h_bins = 50;
int s_bins = 60;
int histSize[] = { h_bins,s_bins };
float h_range[] = { 0,256 };
float s_range[] = { 0,180 };
const float* range[] = { h_range,s_range };
int channels[] = { 0,1 };
//创建存储直方图的MatND类的实例
MatND baseHist;
MatND halfDownHist;
MatND testHist1;
MatND testHist2;
//计算基准图像,两张测试图像,半身基准图像的HSV直方图
calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize,
range, true, false);
normalize(baseHist, baseHist, 0, 1, NORM_MINMAX, -1);
calcHist(&hsvImage_halfDown, 1, channels, Mat(), halfDownHist, 2, histSize,
range, true, false);
normalize(halfDownHist, halfDownHist, 0, 1, NORM_MINMAX, -1);
calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize,
range, true, false);
normalize(testHist1, testHist1, 0, 1, NORM_MINMAX, -1);
calcHist(&hsvImage_test2, 1, channels, Mat(), testHist2, 2, histSize,
range, true, false);
normalize(testHist2, testHist2, 0, 1, NORM_MINMAX, -1);
//按顺序使用四种对比标准图像的直方图与其余各直方图进行对比
for (int i = 0; i < 4; i++) {
int compare_method = i;
double base_base = compareHist(baseHist, baseHist, compare_method);
double base_half = compareHist(baseHist, halfDownHist, compare_method);
double base_test1 = compareHist(baseHist, testHist1, compare_method);
double base_test2 = compareHist(baseHist, testHist2, compare_method);
//输出结果
cout << "\n方法" << i+1 << "匹配结果如下";
cout << "\n【基准图-基准图】" << base_base << " ";
cout << "\n【基准图-半身图】" << base_half << " ";
cout << "\n【基准图-测试图1】" << base_test1 << " ";
cout << "\n【基准图-测试图2】" << base_test2 << " ";
}
waitKey();
return 0;
}


反向投影是一种记录给定图像的像素与直方图模型中的像素分布的吻合程度的方法。
说得简单些:对于Back Projection,你计算一个特征的直方图模型,然后用它来寻找图像中的这个特征。
应用实例:如果你有一个肉色的直方图(例如,色相-饱和度直方图),那么你可以用它来寻找图像中的肉色区域。
我们用皮肤的例子来解释这个问题:
假设你已经根据下面的图片得到了一个皮肤直方图(色相-饱和度)。这个直方图除了将是我们的模型直方图(我们知道它代表了皮肤色调的一个样本)。你应用了一些遮罩,只捕捉皮肤区域的直方图:
现在,让我们想象一下,你得到另一个像下面这样的手部图像(测试图像):(连同其各自的直方图)

我们要做的是使用我们的模型直方图(我们知道它代表皮肤色调)来检测测试图像中的皮肤区域。以下是具体步骤

反向投影用于在输入图像中找与特定图像最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
void calcBackProject(const Mat* images, int nimages, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true)
将输入阵列中的指定通道复制到输出阵列的指定通道。

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
#define WINDOW_NAME1 "原始图"
Mat g_srcImage, g_hsvImage, g_hueImage;
int g_bins = 30;
//回调函数
void on_BinChange(int, void*) {
MatND hist;
int histSize = MAX(g_bins, 2);
float hue_range[] = { 0,180 };
const float* ranges = { hue_range };
calcHist(&g_hueImage,1,0,Mat(),hist,1,&histSize,&ranges,true,false);
normalize(hist, hist, 0, 255, NORM_MINMAX, -1);
//计算反向投影
MatND backproj;
calcBackProject(&g_hueImage, 1, 0, hist, backproj, &ranges, 1, true);
imshow("反向投影图", backproj);
//绘制直方图的参数准备
int w = 400, h = 400;
int bin_w = cvRound((double)w / histSize);
Mat histImg = Mat::zeros(w, h, CV_8UC3);
//绘制直方图
for (int i = 0; i < g_bins; i++) {
rectangle(histImg,
Point(i * bin_w, h),
Point((i + 1) * bin_w, h - cvRound(hist.at<float>(i) * h / 255.0)),
Scalar(100, 123, 255),1);
}
imshow("直方图", histImg);
}
int main() {
g_srcImage = imread("../../image/1.tif");
cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);
g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
int ch[] = { 0,0 };
mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);
namedWindow(WINDOW_NAME1);
createTrackbar("色调组距", WINDOW_NAME1, &g_bins, 180, on_BinChange);
on_BinChange(0, 0);
imshow(WINDOW_NAME1, g_srcImage);
waitKey();
}

模板匹配是一种寻找图像中与模板图像(补丁)相匹配(相似)的区域的技术。
虽然补丁必须是一个矩形,但可能并非所有的矩形都是相关的。在这种情况下,可以用一个遮罩来隔离应该用来寻找匹配的那部分补丁。
我们需要两个主要组成部分:

通过滑动,我们的意思是每次移动一个像素的补丁(从左到右,从上到下)。在每一个位置,都会计算出一个度量,因此它代表了该位置的匹配度有多 "好 "或 “坏”(或者该补丁与源图像的那个特定区域有多相似)。

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。