DrGraph原理示教 - OpenCV 4 功能 - 直方图

OpenCV直方图是一种可以对整幅图的灰度分布进行整体了解的图示。它是带有像素值(从0到255,不总是)的图在X轴上,在y轴上的图像对应的像素个数。通过观察图像的直方图,我们可以直观的了解图像的对比度、亮度、亮度分布等。
在直方图中,横坐标表示图像中各个像素点的灰度级,纵坐标表示具有该灰度级的像素个数。直方图的左边部分显示了图像中较暗像素的数量,右边区域显示了更明亮的像素。
直方图是非常常用的图像处理方法,有时在很多图像预处理中能起到特别好的效果。

一维直方图

OpenCV中,直方图是调用calxHist函数,该函数的参数比较多,不太好理解

The function cv::calcHist calculates the histogram of one or more arrays. The elements of a tuple used
to increment a histogram bin are taken from the corresponding input arrays at the same location. The
sample below shows how to compute a 2D Hue-Saturation histogram for a color image. :
@include snippets/imgproc_calcHist.cpp

@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same
size. Each of them can have an arbitrary number of channels.
@param nimages Number of source images.
@param channels List of the dims channels used to compute the histogram. The first array channels
are numerated from 0 to images[0].channels()-1 , the second array channels are counted from
images[0].channels() to images[0].channels() + images[1].channels()-1, and so on.
@param mask Optional mask. If the matrix is not empty, it must be an 8-bit array of the same size
as images[i] . The non-zero mask elements mark the array elements counted in the histogram.
@param hist Output histogram, which is a dense or sparse dims -dimensional array.
@param dims Histogram dimensionality that must be positive and not greater than CV_MAX_DIMS
(equal to 32 in the current OpenCV version).
@param histSize Array of histogram sizes in each dimension.
@param ranges Array of the dims arrays of the histogram bin boundaries in each dimension. When the
histogram is uniform ( uniform =true), then for each dimension i it is enough to specify the lower
(inclusive) boundary \f$L_0\f$ of the 0-th histogram bin and the upper (exclusive) boundary
\f$U_{\texttt{histSize}[i]-1}\f$ for the last histogram bin histSize[i]-1 . That is, in case of a
uniform histogram each of ranges[i] is an array of 2 elements. When the histogram is not uniform (
uniform=false ), then each of ranges[i] contains histSize[i]+1 elements:
\f$L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1}\f$
. The array elements, that are not between \f$L_0\f$ and \f$U_{\texttt{histSize[i]}-1}\f$ , are not
counted in the histogram.
@param uniform Flag indicating whether the histogram is uniform or not (see above).
@param accumulate Accumulation flag. If it is set, the histogram is not cleared in the beginning
when it is allocated. This feature enables you to compute a single histogram from several sets of
arrays, or to update the histogram in time.
*/
CV_EXPORTS 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 );

简单化理解,那就是hist参数之前的为输入参数,其余的为输出参数。
dims指定直方图的维数,可以先理解1维的。
因为calcHist函数可以用于多维,所以它的参数也要支持多维。其实嘛,简单点多好,多用几个函数分别实现相应多维,用得多的一二维直方图就用得轻松了。
正常使用,calcHist就针对一维处理。所以要用的时候,先需要将彩色图像灰度化,或者split取得各通首图像分别应用calcHist,然后相应算后再合并处理。如果只是想看直方图,那就直接画出来。


  		std::vector<Mat> mv;
   		split(dstMat, mv);  
        int histSize[] = { bins };
        float rgb_ranges[] = { 0, r };
        const float * ranges[] = { rgb_ranges };
        dstMat = CvHelper::ToMat_BGR(dstMat);
        int channels[] = { 0 };
        Mat b_hist, g_hist, r_hist;
        if(channelType == 0 || channelType == 3 || channelType == 4 || channelType == 6)    // B
            calcHist(&mv[0], 1, channels, Mat(), b_hist, 1, histSize, ranges, true, false);
        if(channelType == 1 || channelType == 3 || channelType == 5 || channelType == 6)    // G
            calcHist(&mv[1], 1, channels, Mat(), g_hist, 1, histSize, ranges, true, false);
        if(channelType == 2 || channelType == 4 || channelType == 5 || channelType == 6)    // R
            calcHist(&mv[2], 1, channels, Mat(), r_hist, 1, histSize, ranges, true, false);
        double maxVal = 0;
        int hist_w = 512;
        int hist_h = 400;
        int bin_w = cvRound((double)hist_w / histSize[0]);
        Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
        normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
        normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
        normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
        for(int i = 1; i < histSize[0]; ++i) {
            if(r_hist.empty() == false)
                line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
                     Point(bin_w * i, hist_h - cvRound(r_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA, 0);
            if(g_hist.empty() == false)
                line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
                     Point(bin_w * i, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA, 0);
            if(b_hist.empty() == false)
                line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
                     Point(bin_w * i, hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA, 0);
        }
        dstMat = histImage;

在这里插入图片描述
在这里插入图片描述
OpenCV 2中,实现calcHist的代码为

	static void calcHist(const Mat* images, int nimages, const int* channels,
		const Mat& mask, SparseMat& hist, int dims, const int* histSize,
		const float** ranges, bool uniform, bool accumulate, bool keepInt) {
		size_t i, N;

		if (!accumulate)
			hist.create(dims, histSize, CV_32F);
		else {
			SparseMatIterator it = hist.begin();
			for (i = 0, N = hist.nzcount(); i < N; i++, ++it) {
				Cv32suf* val = (Cv32suf*)it.ptr;
				val->i = cvRound(val->f);
			}
		}

		vector<uchar*>ptrs;
		vector<int>deltas;
		vector<double>uniranges;
		Size imsize;

		CV_Assert(!mask.data || mask.type() == CV_8UC1);
		histPrepareImages(images, nimages, channels, mask, dims, hist.hdr->size,
			ranges, uniform, ptrs, deltas, imsize, uniranges);
		const double* _uniranges = uniform ? &uniranges[0] : 0;

		int depth = images[0].depth();
		if (depth == CV_8U)
			calcSparseHist_8u(ptrs, deltas, imsize, hist, dims, ranges,
			_uniranges, uniform);
		else if (depth == CV_16U)
			calcSparseHist_<ushort>(ptrs, deltas, imsize, hist, dims, ranges,
			_uniranges, uniform);
		else if (depth == CV_32F)
			calcSparseHist_<float>(ptrs, deltas, imsize, hist, dims, ranges,
			_uniranges, uniform);
		else
			CV_Error(CV_StsUnsupportedFormat, "");

		if (!keepInt) {
			SparseMatIterator it = hist.begin();
			for (i = 0, N = hist.nzcount(); i < N; i++, ++it) {
				Cv32suf* val = (Cv32suf*)it.ptr;
				val->f = (float)val->i;
			}
		}
	}

}

void cv::calcHist(const Mat* images, int nimages, const int* channels,
	InputArray _mask, SparseMat& hist, int dims, const int* histSize,
	const float** ranges, bool uniform, bool accumulate) {
	Mat mask = _mask.getMat();
	calcHist(images, nimages, channels, mask, hist, dims, histSize, ranges,
		uniform, accumulate, false);
}

void cv::calcHist(InputArrayOfArrays images, const vector<int>& channels,
	InputArray mask, OutputArray hist, const vector<int>& histSize,
	const vector<float>& ranges, bool accumulate) {
	int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz =
		(int)channels.size();
	int nimages = (int)images.total();

	CV_Assert(nimages > 0 && dims > 0);
	CV_Assert(rsz == dims*2 || (rsz == 0 && images.depth(0) == CV_8U));
	CV_Assert(csz == 0 || csz == dims);
	float* _ranges[CV_MAX_DIM];
	if (rsz > 0) {
		for (i = 0; i < rsz / 2; i++)
			_ranges[i] = (float*)&ranges[i * 2];
	}

	AutoBuffer<Mat>buf(nimages);
	for (i = 0; i < nimages; i++)
		buf[i] = images.getMat(i);

	calcHist(&buf[0], nimages, csz ? &channels[0] : 0, mask, hist, dims,
		&histSize[0], rsz ? (const float**)_ranges : 0, true, accumulate);
}

看似有点麻烦,其实一点也没必要去理解这个代码,知道其作用就OK

直方图均衡化

直方图均衡化,调用equalizeHist即可。同样也是针对单通道进行处理

  		std::vector<Mat> mv;
   		split(dstMat, mv);  
   		Mat b_hist, g_hist, r_hist;
        if(channelType == 0 || channelType == 3 || channelType == 4 || channelType == 6)    // B
            equalizeHist(mv[0], mv[0]);
        if(channelType == 1 || channelType == 3 || channelType == 5 || channelType == 6)    // G
            equalizeHist(mv[1], mv[1]);
        if(channelType == 2 || channelType == 4 || channelType == 5 || channelType == 6)    // R
            equalizeHist(mv[2], mv[2]);
        merge(mv, dstMat);

在这里插入图片描述

直方图均衡化(Histogram Equalization)是一种图像增强技术,其目的是通过对图像的直方图进行调整,使得图像的灰度分布更加均匀,从而提高图像的对比度和整体质量。
在直方图均衡化过程中,首先计算图像的直方图,即统计图像中每个灰度级出现的次数或频率。然后,根据直方图的分布情况,对灰度级进行重新映射,使得每个灰度级在整个灰度范围内具有相同的出现概率或频率。
具体实现时,可以通过计算累积直方图来确定灰度级的映射关系。累积直方图表示了灰度级小于等于某个值的像素数量占总像素数量的比例。根据累积直方图,可以将原始的灰度级映射到新的灰度级,使得每个灰度级在新的灰度范围内具有相同的出现概率。
直方图均衡化的效果是使图像的灰度分布更加均匀,从而增强图像的对比度和细节。它可以用于改善图像的视觉效果,特别是在低对比度或亮度不均匀的情况下。
需要注意的是,直方图均衡化可能会导致图像的局部信息丢失,因为它是对整个图像进行全局的灰度调整。在实际应用中,需要根据具体情况选择是否使用直方图均衡化以及如何调整参数以获得最佳效果。

自适应直方图均衡化

自适应直方图均衡化(Adaptive Histogram Equalization,AHE)是一种改进的直方图均衡化技术,它在保留图像细节和对比度的同时,对局部区域进行自适应的灰度调整。
传统的直方图均衡化是对整个图像进行全局的灰度变换,可能会导致图像的局部信息丢失。而自适应直方图均衡化则考虑了图像的局部上下文信息,根据每个像素周围的像素分布来调整其灰度级。
自适应直方图均衡化的基本思路如下:
将图像划分为多个子区域(通常是矩形或方形)。
对每个子区域计算其直方图,并进行均衡化操作。
使用均衡化后的子区域直方图对该区域内的像素进行灰度级调整。
通过将图像划分为较小的子区域,可以更好地适应图像中不同区域的灰度分布特征。每个子区域的直方图均衡化操作是独立进行的,从而能够保留图像的局部细节和对比度。
自适应直方图均衡化通常可以提高图像的对比度和细节,尤其在具有亮度不均匀或局部对比度低的情况下效果更为明显。它在图像增强、图像处理和计算机视觉等领域有广泛的应用。
自适应直方图均衡化(Adaptive Histogram Equalization,AHE)和直方图均衡化(Histogram Equalization,HE)都是图像增强技术,用于改善图像的对比度和视觉效果。它们的主要区别在于处理图像的方式。
直方图均衡化是一种全局的方法,它对整幅图像进行均衡化处理。通过计算图像的直方图,然后对灰度级进行重新映射,使得图像的灰度分布更加均匀。这样可以增强图像的对比度,但可能会导致图像的局部细节丢失。
自适应直方图均衡化是对直方图均衡化的改进,它考虑了图像的局部上下文信息。AHE 将图像划分为多个子区域,并对每个子区域进行独立的均衡化处理。这样可以更好地保留图像的局部细节和对比度。
通过将图像划分为较小的子区域,可以更好地适应图像中不同区域的灰度分布特征。每个子区域的直方图均衡化操作是独立进行的,从而能够保留图像的局部细节和对比度。
自适应直方图均衡化在保留图像细节和对比度方面通常比全局的直方图均衡化更有效。它在图像增强、图像处理和计算机视觉等领域有广泛的应用。
其实,说得太多,不知道咋用或用的效果,也是意义不大,至少理解不深,代码倒是很简单

        double clipLimit = GetParamValue_Double(paramIndex++);
        int sizeX = GetParamValue_Int(paramIndex++);
        int sizeY = GetParamValue_Int(paramIndex++);
        auto clahe = createCLAHE(clipLimit, Size(sizeX, sizeY));
        Mat b_hist, g_hist, r_hist;
        if(channelType == 0 || channelType == 3 || channelType == 4 || channelType == 6)    // B
            clahe->apply(mv[0], mv[0]);
        if(channelType == 1 || channelType == 3 || channelType == 5 || channelType == 6)    // G
            clahe->apply(mv[1], mv[1]);
        if(channelType == 2 || channelType == 4 || channelType == 5 || channelType == 6)    // R
            clahe->apply(mv[2], mv[2]);
        merge(mv, dstMat);

在这里插入图片描述
反正我是没太理解该咋用,只是用了有图像有变化,这些参数的调整,以后再慢慢理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/298342.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt——TCP UDP网络编程

目录 前言正文一、TCP二、UDP1、基本流程2、必备知识 三、代码层级1、UDP服务端 END、总结的知识与问题1、如何获取QByteArray中某一字节的数据&#xff0c;并将其转为十进制&#xff1f;2、如何以本年本月本日为基础&#xff0c;获取时间戳&#xff0c;而不以1970为基础&#…

MySQL之数据类型建表以及约束

SELECT(查询) 查询操作用于从数据库中检索数据 查询可以基于不同的条件&#xff0c;如字段值、范围、排序等 查询结果可以返回单个记录或多个记录 查询指定列 select 列名 from 表名 列名&#xff1a;代表从指定的列名中查找 , 如果是查找对应的多列&#xff0c;则用英文…

Linux部署Yearning并结合内网穿透工具实现公网访问本地web管理界面

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

Ps 滤镜:高反差保留

Ps菜单&#xff1a;滤镜/其它/高反差保留 Filter/Others/High Pass 高反差保留 High Pass滤镜常用于锐化、保护纹理、提取线条等图像编辑工作流程中。它的工作原理是&#xff1a;只保留显示图像中的高频信息&#xff08;即图像中的细节和边缘区域&#xff09;&#xff0c;而图像…

MongoDB索引详解

概述 索引是一种用来快速查询数据的数据结构。BTree 就是一种常用的数据库索引数据结构&#xff0c;MongoDB 采用 BTree 做索引&#xff0c;索引创建 colletions 上。MongoDB 不使用索引的查询&#xff0c;先扫描所有的文档&#xff0c;再匹配符合条件的文档。使用索引的查询&…

【数据结构】二叉树的概念及堆

前言 我们已经学过了顺序表、链表、栈和队列这些属于线性结构的数据结构&#xff0c;那么下面我们就要学习我们第一个非线性结构&#xff0c;非线性结构又有哪些值得我们使用的呢&#xff1f;那么接下来我们就将谈谈树的概念了。 1.树的概念与结构 1.1树的概念 树是一种非线性…

Microsoft edge@常见问题@由组织管理@策略组@版本问题

文章目录 本地edge浏览器由组织管理功能受限检查例:侧边栏功能被禁用解出限制(删除相关注册表条目)解除限制检查refs 页面加载问题this page having a problem 禁止edge更新refs 版本回滚 本地edge浏览器由组织管理功能受限检查 浏览器输入edge://management/检查通过修改注册表…

【数据仓库与联机分析处理】多维数据模型

目录 一、数据立方体 二、数据模型 &#xff08;一&#xff09;星形模型 &#xff08;二&#xff09;雪花模式 &#xff08;三&#xff09;事实星座模式 三、多维数据模型中的OLAP操作 &#xff08;一&#xff09;下钻 &#xff08;二&#xff09;上卷 &#xff08;三…

宏电股份5G RedCap终端产品助力深圳极速先锋城市建设

12月26日&#xff0c;“全城全网&#xff0c;先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行&#xff0c;宏电股份携一系列5G RedCap终端产品应邀参与创新发布会&#xff0c;来自全国5G生态圈的各界嘉宾、专家学者济济一堂&#xff0c;共探信息化数字化创新…

mysql之视图mysql连接案例索引

文章目录 一、视图1.1 含义1.2 操作1.2.1 创建视图1.2.2 视图的修改1.2.3 删除视图1.2.4 查看视图 二、连接案例01)查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数02)查询同时存在" 01 "课程和" 02 "课程的情况03&#xff0…

ios 裁剪拼装图片

//1.获取图片UIImage *image [UIImage imageNamed:"123.jpg"];//处理图片//2.获取图片的长度long length image.size.width/4;//3.图片顶点索引long indices[] {length * 2,length,//右 right0,length,//左 leftlength,0,//上 toplength,length * 2,//底 bottomle…

Rustdesk打开Win10 下客户端下面服务不会自启,显示服务未运行

环境: Rustdesk1.19 问题描述: Rustdesk打开Win10 下客户端下面服务不会自启,显示服务未运行 解决方案: 1.查看源代码 pub async fn start_all() {crate::hbbs_http::sync::start();let mut nat_tested = false;check_zombie()

SwinTransformer

patch embedding (b,3,224,224)->(b,N,96) N:patch数量 为每个stage中的每个Swin Transformer block设置drop_rate&#xff0c;根据设置[2,2,6,2]&#xff0c;每个Swin Transformer block的drop_path为0~0.1等间距采样的12个小数&#xff0c;参数0.1也可以更改。还有个drop参…

网络安全红队常用的攻击方法及路径

一、信息收集 收集的内容包括目标系统的组织架构、IT资产、敏感信息泄露、供应商信息等各个方面&#xff0c;通过对收集的信息进行梳理&#xff0c;定位到安全薄弱点&#xff0c;从而实施下一步的攻击行为。 域名收集 1.备案查询 天眼查爱企查官方ICP备案查询 通过以上三个…

数据矩阵集成可提高印刷电路板识别的准确性

在复杂的印刷电路板 (PCB) 世界中&#xff0c;准确的电路板元件识别对于简化故障排除至关重要。它确保电子设备高效运行。 本文将探讨数据矩阵码在提高 PCB 零件识别效率方面的作用。数据矩阵码提供了一种简单的解决方案来编码和解码与 PCB 组件相关的信息&#xff0c;在简化识…

安卓Android Studioy读写NXP ICODE2 15693标签源码

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-21818769070.11.4391789eCLwm3t&id615391857885 <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xm…

『C++成长记』日期类的实现

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;C &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、日期类的实现 &#x1f4d2;1.1日期类功能 &#x1f4d2;1.2拷贝日期 &#…

C++面试宝典第13题:计算餐厅账单

题目 假如你是一家餐厅的收银员,需要编写一个程序来计算顾客的账单。程序应该能够接受顾客点的菜品和数量,并根据菜品的单价计算出总价。另外,程序还应该能够处理折扣和优惠券,并输出最终的账单金额。 解析 这道题主要考察应聘者使用面向对象的设计方法来解决实际问题的能力…

基于旗鱼算法优化的Elman神经网络数据预测 - 附代码

基于旗鱼算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于旗鱼算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于旗鱼优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

Pandas DataFrame中将True/False映射到1/0

在本文中&#xff0c;我们将看到如何在Pandas DataFrame中将True/False映射到1/0。True/False到1/0的转换在执行计算时至关重要&#xff0c;并且可以轻松分析数据。 1. replace方法 在这个例子中&#xff0c;我们使用Pandas replace()方法将True/False映射到1/0。在这里&…
最新文章