c++版opencv基础学习Day4_图像金字塔及图像直方图

图像金字塔

什么是图像金字塔

图像金字塔是以一系列以金字塔形状排列的,自底向上分辨率逐渐降低的图像合集

金字塔是同一图像不同分辨率的子图集合(每层图像的宽度和高度一般都是原来的2倍数),有向下和向上采样之分

分类:

高斯金字塔:通过高斯模糊滤波+向下采样

拉普拉斯金字塔:在高斯金字塔的基础上,为了实现图像重建而存在

拉普拉斯金字塔实际上是为了实现高斯金字塔图像重构而存在的金字塔(即基于高斯金字塔的实现的金字塔),其每层的图像实际上是高斯金字塔同层的图片与高斯金字塔下一层图片的差值图像,即拉普拉斯金字塔即为差值金字塔。对金字塔中的小图像进行向上采样以获取完整的大尺寸高分辨率图像

降采样

        应用于高斯金字塔

    作用:通过高斯卷积使图像模糊,并对其进行下采样。(宽高各缩小一倍)
    尺寸:默认情况下,输出图像的大小计算为size=((src.cols+1)/2,(src.rows+1)/2)。

该函数执行高斯金字塔构造的下采样步骤:将源图像与高斯卷积核进行卷积(模糊化),然后删除偶数行和偶数列来对图像进行下采样。
 

#include <opencv2/imgproc.hpp>
函数说明:void cv::pyrDown( InputArray src, OutputArray dst, const Size &dstsize = Size(), int borderType = BORDER_DEFAULT);
输入参数:
				src					输入图像。
				dst					输出图像。它具有指定的大小、且与src具有相同的类型。
				dstsize				输出图像的大小。
				borderType = BORDER_DEFAULT		边界类型(即边界填充方式)。默认且只支持BORDER_DEFAULT。
							cv::BORDER_REFLECT_101 = 4 			gfedcb|abcdefgh|gfedcba			反射法。以最边缘像素为轴
							cv::BORDER_DEFAULT = 7 				same as BORDER_REFLECT_101

上采样

       用于帮助计算出拉普拉斯金字塔

    作用:对图像进行上采样,然后通过高斯卷积使其模糊。(宽高各放大一倍)
    尺寸:默认情况下,输出图像的大小计算为size=(src.cols*2,src.rows*2)。

该函数执行高斯金字塔构造的上采样步骤:通过均匀地隔行隔列的方式,填充全零行和全零列来对源图像进行上采样,然后将结果与(cv::pyrDown的相同高斯卷积核乘以4)进行卷积(模糊化)。
 

#include <opencv2/imgproc.hpp>
函数说明:void cv::pyrUp( InputArray src, OutputArray dst, const Size &dstsize = Size(), int borderType = BORDER_DEFAULT);
输入参数:
				src					输入图像。
				dst					输出图像。它具有指定的大小、且与src具有相同的类型。
				dstsize				输出图像的大小。
				borderType = BORDER_DEFAULT		边界类型(即边界填充方式)。默认且只支持BORDER_DEFAULT。
							cv::BORDER_REFLECT_101 = 4 			gfedcb|abcdefgh|gfedcba			反射法。以最边缘像素为轴
							cv::BORDER_DEFAULT = 7 				same as BORDER_REFLECT_101

栗子

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{

	string img_path1 = "D:/系统默认/桌面/RM/sha.jpeg";
	//string img_path2 = "D:/系统默认/桌面/RM/tou.jpeg";

	Mat src = imread(img_path1, 1);
	//Mat src2 = imread(img_path2, 1);
	
	if (src.empty() ) {
		cout << "can't read image!!" << endl;
		return -1;
	}

	Mat img_up, img_down;
	pyrUp(src, img_up, Size(src.cols * 2, src.rows * 2));
	pyrDown(src, img_down, Size((src.cols + 1) / 2, (src.rows + 1) / 2));

	imshow("src", src);
	imshow("img_up", img_up);
	imshow("img_down", img_down);
	


	waitKey();
	return 0;

	
}

图像直方图

直方图是数值数据分布的精确图形表示。

用一表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数

可以借助观察该直方图了解需要如何调整亮度分布的直方图。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。计算机视觉邻域常借助图像直方图来实现图像的二值化。

计算一个/多个数组的直方图
 

#include <opencv2/imgproc.hpp>
函数说明:void cv::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 );
输入参数:
				(1)images					输入数组。它们都应该具有相同的深度,CV_8U、CV_16U或CV_32F,并且具有相同的尺寸。它们中的每一个都可以具有任意数量的通道。
				(2)nimages				输入图像的数量。
				(3)channels				选择输入图像的通道。
				(4)mask					掩膜。与输入数组大小相同。None表示处理整个图像(常用),1表示需要处理的部分,0表示不需要处理。
				(5)hist					输出的直方图。是一个密集或稀疏的dims维数组。
				(6)dims					直方图维度。必须为正且不大于CV_MAX_DIMS(在当前OpenCV版本中等于32)。
				(7)histSize				灰度级个数(柱子数量)。一般256。
				(8)ranges					像素值范围。一般[0, 255]。
									11、当直方图是均匀的(uniform =true)时,,每个范围[i]是一个包含2个元素的数组。
									22、当直方图不均匀时(uniform=false),不包含L0和UhistSize[i]−1之间的数组元素。
				(9)uniform = true			直方图是否均匀的标志(见上文)。
				(10)accumulate = false	累加标志。如果true,则不清除直方图,直接累加计算多个数组的直方图,或者及时更新直方图。

比较两个直方图并返回指标

#include <opencv2/imgproc.hpp>
函数说明:double cv::compareHist( InputArray H1, InputArray H2, int method );
输入参数:
				(1)H1					输入第一个直方图。
				(2)H2					输入第二个直方图。(大小类型与H1相同)
				(3)method				比较方法。详细公式见官网
								cv::HISTCMP_CORREL = 0				相关性
								cv::HISTCMP_CHISQR = 1 				卡方	
								cv::HISTCMP_INTERSECT = 2 			相交
								cv::HISTCMP_BHATTACHARYYA = 3 		巴塔查里亚距离
								cv::HISTCMP_HELLINGER = 3 			HISTCMP_BHATTACHARYYA的同义词。
								cv::HISTCMP_CHISQR_ALT = 4 			选择卡方
								cv::HISTCMP_KL_DIV = 5 				Kullback-Leibler散度

 直方图均衡化

将输入的灰度图像直方图通过累积分布函数转换成近似于均匀分布的图像,从而增强图像的对比度。

  • 优点:适用于像素值分布比较均衡的图像。
  • 缺点:对于过亮或过暗的区域,就差强人意(但可以使用自适应,将超过阈值部分裁剪到其他灰度级)。

直方图均衡化详细介绍:OpenCV 直方图均衡化_opencv直方图均衡化_杨 戬的博客-CSDN博客

 步骤:

  1. 加载源图像
  2. 转为灰度图
  3. EqualizeHist 对直方图均衡化
  4. 显示均衡化后图像.
#include <opencv2/imgproc.hpp>
函数说明:void cv::equalizeHist( InputArray src,OutputArray dst );
输入参数:
				(1)src				输入8位单通道图像。
				(2)dst				与src大小和类型相同的目标图像。

 自适应直方图均衡化

自适应直方图均衡化:会过度放大图像中相同区域的噪声。
限制对比度自适应直方图均衡:对每个小区域都使用对比度幅值限制,可以克服AHE的过度放大噪音问题。
 

步骤:

(1)将输入图像均匀切分为M x N个区域,并设置一个对比度限制阈值;
(2)计算每个区域的直方图;
(3)对直方图的每个灰度级进行阈值限制,超过该阈值则直接裁剪,并将裁剪部分 通过直方图均衡化的累积分布函数 进而 均匀分布到其他灰度级 ,最后得到每个区域的重构直方图。
 

#include <opencv2/imgproc.hpp>
函数说明:cv::Ptr<cv::CLAHE> cv::createCLAHE( double clipLimit = 40.0, Size tileGridSize = Size(8, 8) );
输入参数:
				(1)clipLimit = 40.0						对比度限制阈值。
				(2)tileGridSize = Size(8, 8)				网格大小(行和列)。将输入图像划分为大小相等的M × N块。

栗子

建议学栗子的时候,如果不是一天学的回顾一下前面的东西哈

我其实说我,我忘了哈哈哈哈

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{

    //string img_path1 = "D:/系统默认/桌面/RM/sha.jpeg";

	string img_path1 = "D:/系统默认/桌面/RM/tou.jpeg";
	Mat src = cv::imread(img_path1, 1);
	if (!src.data)
	{
		cout << "can't read image!" << std::endl;
		return -1;
	}

	//直方图

	//4.1、通道分割
	vector<Mat> bgr;
	split(src, bgr);
	//split函数,通道分离函数,将原图,分解到vector容器中
	
	//4.2、计算直方图
	Mat b_hist, g_hist, r_hist;
	int numbins = 256;						//灰度级个数(柱子数量)。一般256。
	float range[] = { 0, 256 };				//像素值范围。一般[0, 255]。
	const float* histRange = { range };
	//分别计算每个通道的直方图
	calcHist(&bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange);
	calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange);
	calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange);

	//4.3、新建空白直方图
	int hist_width = 512;
	int hist_height = 300;
	Mat hist_Image(hist_height, hist_width, CV_8UC3, Scalar(20, 20, 20));
	//创建Mat对象

	//4.4、标准化:将图像直方图的高度与输出直方图的高度保持一致
	normalize(b_hist, b_hist, 0, hist_height, NORM_MINMAX);
	normalize(g_hist, g_hist, 0, hist_height, NORM_MINMAX);
	normalize(r_hist, r_hist, 0, hist_height, NORM_MINMAX);
	//归一化函数   
	// NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。

	//4.5、线图
	int binStep = cvRound((float)hist_width / (float)numbins);
	for (int i = 1; i < numbins; i++)
	{
		//11、将宽度除以数组大小,进行标准化。
		//22、统计像素值在[0, 255]中的数量。
		//33、绘制曲线。x范围[i-1, i];y是对应xi中的像素值。
		line(hist_Image, Point(binStep * (i - 1), hist_height - cvRound(b_hist.at<float>(i - 1))),
			Point(binStep * (i), hist_height - cvRound(b_hist.at<float>(i))),Scalar(255, 0, 0));
		line(hist_Image, Point(binStep * (i - 1), hist_height - cvRound(g_hist.at<float>(i - 1))),
			Point(binStep * (i), hist_height - cvRound(g_hist.at<float>(i))),Scalar(0, 255, 0));
		line(hist_Image, Point(binStep * (i - 1), hist_height - cvRound(r_hist.at<float>(i - 1))),
			Point(binStep * (i), hist_height - cvRound(r_hist.at<float>(i))),Scalar(0, 0, 255));
	}

	//比较直方图并返回指标
	double cpH1 = compareHist(b_hist, g_hist, HISTCMP_CORREL);//相关性
	double cpH2 = compareHist(b_hist, g_hist, HISTCMP_CHISQR);//卡方
	double cpH3 = compareHist(b_hist, g_hist, HISTCMP_INTERSECT);//相交
	double cpH4 = compareHist(b_hist, g_hist, HISTCMP_BHATTACHARYYA);//巴塔查理亚距离
	double cpH5 = compareHist(b_hist, g_hist, HISTCMP_HELLINGER);//同上
	double cpH6 = compareHist(b_hist, g_hist, HISTCMP_CHISQR_ALT);//选择卡方
	double cpH7 = compareHist(b_hist, g_hist, HISTCMP_KL_DIV);//一种散度
	cout << cpH1 << endl;
	cout << cpH2 << endl;
	cout << cpH3 << endl;
	cout << cpH4 << endl;
	cout << cpH5 << endl;
	cout << cpH6 << endl;
	cout << cpH7 << endl;

	//(6)直方图均衡化
	Mat image_EH0, image_EH1, image_EH2;
	equalizeHist(bgr[0], image_EH0);
	equalizeHist(bgr[1], image_EH1);
	equalizeHist(bgr[2], image_EH2);

	//(7)自适应直方图均衡化
	Mat img_clahe0, img_clahe1, img_clahe2;
	Ptr<CLAHE> clahe = createCLAHE();		//实例化CLAHE算法
	clahe->setClipLimit(4);								//在CLAHE对象上,设置对比度限制阈值
	clahe->setTilesGridSize(Size(8, 8));			//在CLAHE对象上,设置均匀切分的区域
	clahe->apply(bgr[0], img_clahe0);			//在CLAHE对象上,调用.apply()方法(对B通道)来应用直方图均衡化
	clahe->apply(bgr[1], img_clahe1);			//在CLAHE对象上,调用.apply()方法(对G通道)来应用直方图均衡化
	clahe->apply(bgr[2], img_clahe2);			//在CLAHE对象上,调用.apply()方法(对R通道)来应用直方图均衡化

	//(8)显示图像(由于是单通道,故颜色三通道必须都有值)
	imshow("hist", hist_Image);

	imshow("EH0", image_EH0);
	imshow("EH1", image_EH1);
	imshow("EH2", image_EH2);

	imshow("clahe0", img_clahe0);
	imshow("clahe1", img_clahe1);
	imshow("clahe2", img_clahe2);

	waitKey(0);
	return 0;
	
}

学习参考链接

Opencv C++图像处理(全)_c++ opencv 图像处理-CSDN博客

【C++的OpenCV】第八课-OpenCV图像常用操作(五):图像形态学-图像金字塔(Gaussian pyramid、Laplacian pyramid)和向上(下)采样的使用和原理_opencv 图片下采样-CSDN博客

 直方图(opencv)_opencv直方图-CSDN博客

CLAHE算法学习-CSDN博客 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值