一、图像直方图
在分析图像、物体和视频信息的时候,我们经常用直方图来表达我们关注的信息。直方图在计算机视觉中应用广泛。例如,通过判断帧与帧之间边缘和颜色的统计量是否出现巨大变化,来检测视频中场景的变换。在数字图像处理中,通常使用的是灰度直方图,灰度直方图是一种计算代价非常小但很有用的工具,它概括了一幅图像的灰度级信息。灰度直方图是图像灰度级的函数,用来描述每个灰度级在图像矩阵中的像素个数或者占有率。直方图分布较广较均匀的图像对比度高,视觉效果好。
API介绍
void calcHist( 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 );
/*******************************************************************
* images: 输入图
* nimages: 输入图个数
* channels: 统计第几通道
* mask: 掩膜
* hist: 数组存储输出值
* dims: 输出直方图维度
* histSize: 直方图区间
* ranges: 统计像素区间
* uniform: 直方图数组是否归一化处理
* accumulate: 多图时是否累计计算
*********************************************************************/
void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask,SparseMat& hist, int dims,const int* histSize, const float** ranges,bool uniform = true, bool accumulate = false );
/*******************************************************************
* images: 输入图
* nimages: 输入图个数
* channels: 统计第几通道
* mask: 掩膜
* hist: 图像存储输出值
* dims: 输出直方图维度
* histSize: 直方图区间
* ranges: 统计像素区间
* uniform: 直方图数组是否归一化处理
* accumulate: 多图时是否累计计算
*********************************************************************/
void calcHist( InputArrayOfArrays images,const std::vector<int>& channels,InputArray mask, OutputArray hist,const std::vector<int>& histSize,const std::vector<float>& ranges,bool accumulate = false );
/*******************************************************************
* images: 输入图
* channels: 变换矩阵
* mask: 输出图大小
* hist: 数组存储输出值
* histSize: 直方图区间
* ranges: 统计像素区间
* accumulate: 多图时是否累计计算
*********************************************************************/
综合代码
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Hist
{
public:
Hist(string url = "./mm.jpg") :img(imread(url))
{
hist["img"] = img;
}
void TestCalcHist()
{
split(img, bgr);
//准备直方图的参数
Mat Blue, Green, Red;
const int channerl[] = { 0 };
const int histSize[] = { 256 };
float rang[] = { 0,255 };
const float* ranges[] = { rang };
calcHist(&bgr[0], 1, channerl, Mat(), Blue, 1, histSize, ranges);
calcHist(&bgr[1], 1, channerl, Mat(), Green, 1, histSize, ranges);
calcHist(&bgr[2], 1, channerl, Mat(), Red, 1, histSize, ranges);
//绘制直方图
int width = 500;
int height = 300;
hist["hist"] = Mat(height, width, CV_8UC3, Scalar(0, 0, 0));
//归一化处理
normalize(Blue, Blue, 0, 300, NORM_MINMAX);
normalize(Green, Green, 0, 300, NORM_MINMAX);
normalize(Red, Red, 0, 300, NORM_MINMAX);
//比例问题
int step = cvRound(float(width) / float(256)); //每一个点的占比
for (int i = 1; i < 256; i++)
{
line(hist["hist"], Point(step * (i - 1), height - cvRound(Blue.at<float>(i - 1))), Point(step * (i), height - cvRound(Blue.at<float>(i))),Scalar(255,0,0));
line(hist["hist"], Point(step * (i - 1), height - cvRound(Blue.at<float>(i - 1))), Point(step * (i), height - cvRound(Green.at<float>(i))), Scalar(0, 255, 0));
line(hist["hist"], Point(step * (i - 1), height - cvRound(Blue.at<float>(i - 1))), Point(step * (i), height - cvRound(Red.at<float>(i))), Scalar(0, 0, 255));
}
}
void Show()
{
for (auto& v : hist)
{
imshow(v.first, v.second);
}
waitKey(0);
}
protected:
Mat img;
map<string, Mat> hist;
vector<Mat> bgr;
};
int main()
{
unique_ptr<Hist> p(new Hist);
p->TestCalcHist();
p->Show();
return 0;
}
二、图像金字塔
图像金字塔有两种,
- 高斯金字塔:高斯金字塔用来向下采样
- 拉普拉斯金字塔:图像底层图像重建上层未采样图像
在数据图像处理中,就是数据残差,可以对图像进行最大程度的还原,配合高斯金字塔—起使用。
高斯金字塔
高斯金字塔是由底部的最大分辨率图像逐次向下采样得到的一系列图像。最下面的图像分辨率最高,越往上图像分辨率越低。高斯金字塔的向下采样过程是:对于给定的图像先做一次高斯平滑处理,也就是使用一个卷积核对图像进行卷积操作,再对图像采样,去除图像中的偶数行和偶数列,然后就得到一幅图片,对这幅图片再进行上述操作,就可以得到高斯金字塔。
拉普拉斯金字塔
拉普拉斯金字塔与高斯金字塔正好相反,高斯金字塔通过底层图像构建上层图像,而拉普拉斯是通过上层小尺寸的图像构建下层大尺寸的图像。主要应用于图像融合,即是通过残差来还原原图。
图像向上采样是由小图像不断放大的过程。它将图像在每个方向上扩大为原图像的⒉倍,新增的行和列均用0来填充,并使用与“向下采样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值。所有元素都被规范化为4,而不是1。值得注意的是,放大后的图像比原始图像要模糊。
API介绍
//向下采样
void pyrDown( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );
/*******************************************************************
* src: 输入图
* dst: 输出图
* dstsize: 卷积核大小
* borderType: 边界模式
*********************************************************************/
//向上采样
void pyrUp( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );
/*******************************************************************
* src: 输入图
* dst: 输出图
* dstsize: 卷积核大小
* borderType: 边界模式
*********************************************************************/
综合代码
#include <iostream>
#include <string>
#include <map>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Pyr
{
public:
Pyr() :img(imread("20.jpg"))
{
pyr["img"] = img;
}
void TestPyrDown()
{
pyrDown(img, pyr["d1"]);
pyrDown(pyr["d1"], pyr["d2"]);
pyrDown(pyr["d2"], pyr["d3"]);
}
void TestPyrUp()
{
pyrUp(img, pyr["u1"]);
pyrUp(pyr["u1"], pyr["u2"]);
//pyrUp(pyr["u2"], pyr["u3"]);
}
void Show()
{
int i = 0;
for (auto& v : pyr)
{
imshow(v.first, v.second);
moveWindow(v.first, i++ * 100, 100);
}
waitKey(0);
}
protected:
Mat img;
map<string, Mat> pyr;
};
int main()
{
unique_ptr<Pyr> p(new Pyr);
p->TestPyrUp();
p->TestPyrDown();
p->Show();
return 0;
}