当前位置: 首页 > news >正文

Ubuntu系统VScode实现opencv(c++)图像一维直方图

前言

在数字图像处理领域,直方图是一种极为重要的工具,而图像的一维直方图更是其中的基础与核心。一维直方图以简洁而直观的方式,将图像中像素的灰度值分布情况呈现出来,让我们能够快速了解图像的整体亮度、对比度等关键信息。通过对一维直方图的分析,我们可以轻松判断图像是否过亮或过暗,对比度是否合适,进而为后续的图像增强、分割、特征提取等一系列操作提供有力的依据。

直方图概念

实际上,一维直方图就是不同像素值出现频率的统计。如下图:

一维直方图一般是将多通道拆分为单通道,然后统计对应单通道像素出现频率,对于RGB图像来说一般有三个折线。

opencv中已经有相应的函数帮助我们生成直方图的数据,我们先了解每一个参数变量。

calcHist函数

1.函数原型:

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 );

 2.参数介绍:

(1)const Mat* images

输入图像数组。通常传入图像的地址(如 &image)。如果传入多个图像,它们必须具有相同的尺寸和通道数。

(2)int nimages

输入图像的数量。如果只有一个图像,传入 1;如果有多个图像,传入图像数组的长度。

(3)const int* channels

对于灰度图像,通常传入 0(表示单通道)。

对于彩色图像(如 BGR),可以传入 0(蓝色通道)、1(绿色通道)或 2(红色通道)。

如果需要同时计算多个通道的直方图,可以传入一个数组(例如,int channels[] = {0, 1} 表示计算蓝色和绿色通道的直方图)。

(4)InputArray mask:

掩码图像,如果传入掩码,直方图仅计算掩码中非零像素对应的值。

(5)OutputArray hist

输出的直方图。直方图是一个一维或多维数组。

(6)int dims

直方图的维度。对于一维直方图(例如,单通道图像),传入 1。对于多维直方图(例如,计算两个通道的联合直方图),传入相应的维度数(如 2)。

(7)const int* histSize

每个维度的直方图大小。对于一维直方图,传入一个整数值(如 256,表示灰度值范围为 0-255)。对于多维直方图,传入一个数组(例如,int histSize[] = {256, 256},表示两个通道的直方图大小均为 256)。

(8)const float** ranges

每个维度的值范围。对于一维直方图,传入一个包含两个值的数组(如 float range[] = {0, 256},表示灰度值范围为 0-255)。对于一维直方图,传入一个包含两个值的数组(如 float range[] = {0, 256},表示灰度值范围为 0-255)。

在了解每一个参数的作用之后就可以开始使用这个函数了。

函数使用 

对于三通道RGB图像,我们做一维的就是提取每个通道的直方图。那么首先就是分离通道,这里应该不用多说,前面已经知道怎么做了。

 vector<Mat> BGR;split(image,BGR);

接下来我们需要定义上述函数的参数,这里多看就会理解了。主要定义的有两个变量,分别是 const int* histSize和const float** ranges

const int bins[] = {256};
float hranges[] = {0,255};
const float* ranges[1] = {hranges};

其实 bins就是横坐标的取值长度,这里的像素是0-255,所以总共有256个灰度等级,而 ranges则是定义像素值范围的,这里之所以这么定义,是因为如果是多通道的,我们直接在ranges中加入另一个通道的范围值,例如这样:

    float h_ranges[] = {0,180};float s_ranges[] = {0,256};const float* ranges[] = {h_ranges,s_ranges};

接下来,定义三个用于接受三个通道直方图的Mat变量;整体代码就是这样:

    vector<Mat> BGR;split(image,BGR);const int bins[] = {256};float hranges[] = {0,255};const float* ranges[1] = {hranges};Mat b_hist,g_hist,r_hist;calcHist(&BGR[0],1,0,Mat(),b_hist,1,bins,ranges);calcHist(&BGR[1],1,0,Mat(),g_hist,1,bins,ranges);calcHist(&BGR[2],1,0,Mat(),r_hist,1,bins,ranges);

具体数据可视化的代码段我使用辅助工具生成:

        // ---------- 1. 准备画布 ----------int hist_w = 512;          // 画布宽度int hist_h = 400;          // 画布高度int bin_w = cvRound(double(hist_w) / 256);   // 每个 bin 的像素宽度Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0)); // 白底// ---------- 2. 归一化到 [0, hist_h] ----------normalize(b_hist, b_hist, 0, histImage.rows - 20, NORM_MINMAX);normalize(g_hist, g_hist, 0, histImage.rows - 20, NORM_MINMAX);normalize(r_hist, r_hist, 0, histImage.rows - 20, NORM_MINMAX);// ---------- 3. 绘制折线 ----------for (int i = 1; i < 256; ++i){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(255, 0, 0), 2);          // B 通道,蓝色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);          // G 通道,绿色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(0, 0, 255), 2);          // R 通道,红色}// ---------- 4. 显示 ----------imshow("BGR Histogram", histImage);waitKey(0);   // 按任意键关闭窗口

整个Demo的代码如下:

void Demo::calicHist_Demo(Mat &image)
{vector<Mat> BGR;split(image,BGR);const int bins[] = {256};float hranges[] = {0,255};const float* ranges[1] = {hranges};Mat b_hist,g_hist,r_hist;calcHist(&BGR[0],1,0,Mat(),b_hist,1,bins,ranges);calcHist(&BGR[1],1,0,Mat(),g_hist,1,bins,ranges);calcHist(&BGR[2],1,0,Mat(),r_hist,1,bins,ranges);// ---------- 1. 准备画布 ----------int hist_w = 512;          // 画布宽度int hist_h = 400;          // 画布高度int bin_w = cvRound(double(hist_w) / 256);   // 每个 bin 的像素宽度Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0)); // 白底// ---------- 2. 归一化到 [0, hist_h] ----------normalize(b_hist, b_hist, 0, histImage.rows - 20, NORM_MINMAX);normalize(g_hist, g_hist, 0, histImage.rows - 20, NORM_MINMAX);normalize(r_hist, r_hist, 0, histImage.rows - 20, NORM_MINMAX);// ---------- 3. 绘制折线 ----------for (int i = 1; i < 256; ++i){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(255, 0, 0), 2);          // B 通道,蓝色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);          // G 通道,绿色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(0, 0, 255), 2);          // R 通道,红色}// ---------- 4. 显示 ----------imshow("BGR Histogram", histImage);waitKey(0);   // 按任意键关闭窗口
}

运行结果: 

http://www.lryc.cn/news/610178.html

相关文章:

  • 机器学习【六】readom forest
  • 微服务配置管理:Spring Cloud Alibaba Nacos 实践
  • 电子电气架构 ---智能电动汽车嵌入式软件开发过程中的block点
  • Nginx服务做负载均衡网关
  • 36.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--缓存Token
  • FPGA学习笔记——简单的乒乓缓存(RAM)
  • 飞算JavaAI需求转SpringBoot项目沉浸式体验
  • android内存作假通杀补丁(4GB作假8GB)
  • labview连接PLC的三种方式
  • 设计模式(一)——抽象工厂模式
  • ES集群规划与调优
  • 进程间通信:管道与共享内存
  • 移动前后端全栈项目
  • 读写分离有那些坑?
  • 16.8 华为昇腾CANN架构深度实战:3大核心引擎解析与性能优化216%秘籍
  • 手搓TCP服务器实现基础IO
  • falsk windows 服务器部署-解决服务器外无法访问
  • javacc学习笔记 02、JavaCC 语法描述文件的格式解析
  • Sklearn 机器学习 数据聚类 肘部法则选择聚类数目
  • 昇思学习营-模型推理和性能优化学习心得
  • MS-DOS 常用指令集
  • 【清除pip缓存】Windows上AppData\Local\pip\cache内容
  • 我的世界进阶模组开发教程——附魔(2)
  • (二)软件工程
  • 论文阅读笔记:《Dataset Distillation by Matching Training Trajectories》
  • 在CentOS 7上安装配置MySQL 8.0完整指南
  • PyTorch :三角函数与特殊运算
  • MFC-Ribbbon-图标-PS
  • 【秋招笔试】2025.08.03虾皮秋招笔试-第二题
  • 蜜汁整体二分——区间 kth