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

news2024/11/18 7:46:50

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.coloradmin.cn/o/1363144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析——快递电商

一、任务目标 1、任务 总体目的——对账 本项目解决同时使用多个快递发货&#xff0c;部分隔离区域出现不同程度涨价等情形下&#xff0c;如何快速准确核对账单的问题。 1、在订单表中新增一列【运费差异核对】来表示订单运费实际有多少差异&#xff0c;结果为数值。 2、将…

HarmonyOS 开发基础(六)Slider

HarmonyOS 开发基础&#xff08;六&#xff09;Slider Entry Component struct Index {build() {Row() {Column() {// Slider&#xff1a;ArkUI 的基础组件 滑动条组件// options 参数&#xff1a;Slider 基础设置Slider({// 最小值min: 20,// 最大值max: 200,// 当前值value: …

文心一言 VS 讯飞星火 VS chatgpt (173)-- 算法导论13.3 2题

二、用go语言&#xff0c;将关键字41、38、31、12、19、8连续地插入一棵初始为空的红黑树之后&#xff0c;试画出该结果树。 文心一言&#xff1a; 首先&#xff0c;我们需要了解红黑树的性质。红黑树是一种自平衡二叉查找树&#xff0c;其中每个节点要么是红色&#xff0c;要…

使用sentinel作为熔断器

什么是sentinel Sentinel&#xff0c;中文翻译为哨兵&#xff0c;是为微服务提供流量控制、熔断降级的功能&#xff0c;它和Hystrix提供的功能一样&#xff0c;可以有效的解决微服务调用产生的“雪崩”效应&#xff0c;为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维…

7+非肿瘤+WGCNA+机器学习+诊断模型,构思巧妙且操作简单

今天给同学们分享一篇生信文章“Platelets-related signature based diagnostic model in rheumatoid arthritis using WGCNA and machine learning”&#xff0c;这篇文章发表在Front Immunol期刊上&#xff0c;影响因子为7.3。 结果解读&#xff1a; DEGs和血小板相关基因的…

Flink自定义Source模拟数据流

maven依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.…

CSS3 边框border、outline、box-shadow

1 border 语法&#xff1a;border: width style color 2 outline 语法&#xff1a;outline: width style color 2.1 outline-offet MDN解释&#xff1a;用于设置outline与一个元素边缘或边框之间的间隙 即&#xff1a;设置outline相对border外边缘的偏移&#xff0c;可以为…

Python 全栈体系【四阶】(十一)

第四章 机器学习 机器学习&#xff1a; 传统的机器学习&#xff1a;以算法为核心深度学习&#xff1a;以数据和计算为核心 感知机 perceptron&#xff08;人工神经元&#xff09; 可以做简单的分类任务掀起了第一波 AI 浪潮 感知机不能解决线性不可分问题&#xff0c;浪潮…

RouterOS L2TP安装与配置

申明&#xff1a;本文仅针对国内L2TP/PPTP&#xff0c;适用于国内的游戏加速或学术研究&#xff0c;禁止一切利用该技术的翻墙行为。 1. L2TP介绍 L2TP&#xff08;Layer 2 Tunneling Protocol&#xff09;是一种在计算机网络中广泛使用的隧道协议&#xff0c;它被设计用于通过…

java火车查询管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web火车查询管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql…

2023年12月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:数的输入和输出 输入一个整数和双精度浮点数,先将浮点数保留2位小数输出,然后输出整数。 时间限制:1000 内存限制:65536 输入 一行两个数,分别为整数N(不超过整型范围),双精度浮点数F,以一个空格分开。 输出 一行两个数,分…

电子学会C/C++编程等级考试2023年12月(二级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:统计指定范围里的数 给定一个数的序列S,以及一个区间[L, R], 求序列中介于该区间的数的个数,即序列中大于等于L且小于等于R的数的个数。 时间限制:1000 内存限制:65536 输入 第一行1个整数n,分别表示序列的长度。(0 < n ≤…

使用Enterprise Architect绘制架构图

如何使用Enterprise Architect绘制架构图 之前没有使用过Enterprise Architect软件绘制&#xff0c;目前由于工作需求&#xff0c;需要使用Enterprise Architect绘制一些架构图&#xff0c;现在只使用Enterprise Architect绘制过简单的Flow Chart&#xff0c;想请教一下大神们…

如何批量自定义视频画面尺寸

在视频制作和编辑过程中&#xff0c;对于视频画面尺寸的调整是一项常见的需求。有时候&#xff0c;为了适应不同的播放平台或满足特定的展示需求&#xff0c;我们需要对视频尺寸进行批量调整。那么&#xff0c;如何实现批量自定义视频画面尺寸呢&#xff1f;本文将为您揭示这一…

纳尼??Rabbitmq居然被一个逗号给坑了??

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 前言 这个问题发生在部署一套新的环境。搭建一个单节点的Rabbitmq&#xff0c;按照小伙伴写的部署文档搭建的。其中搭建步骤和我…

JetCache源码解析——配置加载

JetCache自动化配置加载 JetCache的配置加载主要是在jetcache-autoconfigure模块中完成的&#xff0c;无论是使用内存缓存LinkedHashMap和caffeine&#xff0c;亦或是通过lettuce、redisson和spring-data-redis来操作Redis服务缓存数据&#xff0c;其自动加载配置的操作基本上…

JSON Crack数据可视化工具结合内网穿透实现公网访问

文章目录 1. 在Linux上使用Docker安装JSONCrack2. 安装Cpolar内网穿透工具3. 配置JSON Crack界面公网地址4. 远程访问 JSONCrack 界面5. 固定 JSONCrack公网地址 JSON Crack 是一款免费的开源数据可视化应用程序&#xff0c;能够将 JSON、YAML、XML、CSV 等数据格式可视化为交互…

redis介绍与数据类型(一)

redis介绍与数据类型 1、redis1.1、数据库分类1.2、NoSQL分类1.3、redis简介1.4、redis应用1.5、如何学习redis 2、redis的安装2.1、Windows安装2.2.1、客户端redis管理工具 2.2、Linux安装&#x1f525;2.2.1、redis核心文件2.2.2、启动方式2.2.3、redis桌面客户端1、redis命令…

windows下载官方正版notepad++

一、前言 notepad是一款非常好用的编辑器&#xff0c;简洁、快速、高效。可是很多时候我们想去官网下载时&#xff0c;百度出来的都是一堆第三方下载地址&#xff0c;捆绑流氓软件&#xff0c;要么就是付费&#xff0c;作为一款优秀开源软件&#xff0c;我们必须要知道正确的下…

反射UnityEditor.GameView设置GamePlayMode分辨率

现在很有游戏考虑横屏适配、竖屏适配、阿拉伯语适配&#xff08;横竖屏&#xff09;导致拼界面变得越来越繁琐。 有很多时候需要记录各个控件的状态。 为了减少操作&#xff0c;特意制作了这个工具&#xff0c;点击用x配置可以自动切换到 宽高分辨率&#xff0c;如果当前没有则…